Skip to content

Instantly share code, notes, and snippets.

@PaulskPt
Last active April 8, 2024 11:23
Show Gist options
  • Select an option

  • Save PaulskPt/86551032942e760910b0fb7fa6e2a1bb to your computer and use it in GitHub Desktop.

Select an option

Save PaulskPt/86551032942e760910b0fb7fa6e2a1bb to your computer and use it in GitHub Desktop.

Revisions

  1. PaulskPt revised this gist Apr 4, 2024. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -833,6 +833,7 @@ def send_to_pushingbox():
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing
    except RuntimeError as e: # can be activated by adafruit_requests, OutOfRetries error
    # or by get_socket. RuntimeError, EHOSTUNREACH errno 118
    print(TAG+f"Error: {e}")
    return # do nothing

  2. PaulskPt revised this gist Apr 4, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -1114,7 +1114,7 @@ def main():
    # if c2 == 30:
    # sys.exit() # Temporary forced end of execution
    if doit:
    set_INT_RTC() # get_time_fm_aio()
    set_INT_RTC()
    curr_tm = ct
    time.sleep(1)
    except ImportError: # e.g.: no module named 'platform' (in file :/lib/Adafruit_IO/Client.py, line 24)
  3. PaulskPt revised this gist Apr 4, 2024. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions dst_PRT.py
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,6 @@
    # See: https://www.epochconverter.com/
    # Values are for timezone Europe/Portugal
    dst = {
    2022:(1648342800, 1667095200), # 2022-03-29 01:00:00 / 2022-10-30 02:00:00
    2023:(1679792400, 1698544800), # 2023-03-26 01:00:00 / 2023-10-29 02:00:00
    2024:(1711846800, 1729994400), # 2024-03-31 01:00:00 / 2024-10-27 02:00:00
    2025:(1743296400, 1761444000), # 2025 03-30 01:00:00 / 2025-10-28 02:00:00
    2026:(1774746000, 1792893600), # 2026-03-29 01:00:00 / 2026-10-25 02:00:00
  4. PaulskPt revised this gist Apr 4, 2024. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -778,7 +778,6 @@ def send_to_pushingbox():
    ret = True
    tmp_s = None
    hum_s = None
    network = magtag.network
    response = None
    stat_result = None
    devid = os.getenv("PUSHING_BOX_DEVID") # device ID on Pushingbox for our Scenario
    @@ -826,12 +825,16 @@ def send_to_pushingbox():
    print("\"", end='\n') # To complete the message to the Serial (REPL) window
    print(TAG+"Data Sent")
    try:
    network = magtag.network
    response = network.fetch(s) # Get the spreadsheet partly
    except OSError as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing
    except RuntimeError as e: # can be activated by adafruit_requests, OutOfRetries error
    print(TAG+f"Error: {e}")
    return # do nothing

    if my_debug:
    print()
  5. PaulskPt revised this gist Apr 4, 2024. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -40,6 +40,7 @@
    """
    import sys
    import os
    import gc
    import supervisor
    import board
    import time
    @@ -630,7 +631,7 @@ def set_INT_RTC():
    s2 = "datetime stamp: "
    dt = None
    internal_RTC = True if is_INT_RTC() else False

    if internal_RTC:
    try:
    dt = ntp.datetime
    @@ -644,7 +645,7 @@ def set_INT_RTC():
    return
    elif err == 116:
    print(TAG+"NTP timed out. Exiting function.")
    return
    return
    else:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    @@ -778,6 +779,7 @@ def send_to_pushingbox():
    tmp_s = None
    hum_s = None
    network = magtag.network
    response = None
    stat_result = None
    devid = os.getenv("PUSHING_BOX_DEVID") # device ID on Pushingbox for our Scenario

    @@ -827,7 +829,7 @@ def send_to_pushingbox():
    response = network.fetch(s) # Get the spreadsheet partly
    except OSError as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing

    @@ -1101,7 +1103,7 @@ def main():
    start = False
    blink_leds() # switch off LEDs
    get_th_direct() # sensor directly connected to MAGTAG board via I2C/Stemma_QT

    gc.collect()
    if not send_to_pushingbox():
    raise KeyboardInterrupt
    else:
  6. PaulskPt revised this gist Apr 3, 2024. 1 changed file with 8 additions and 4 deletions.
    12 changes: 8 additions & 4 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -630,17 +630,21 @@ def set_INT_RTC():
    s2 = "datetime stamp: "
    dt = None
    internal_RTC = True if is_INT_RTC() else False

    if internal_RTC:
    try:
    dt = ntp.datetime
    if not rtc_set:
    rtc_bi.datetime = dt
    rtc_set = True
    except OSError as e:
    if e.args[0] == 116:
    print(TAG+"NTP timed out. Exiting function.")
    err = e.args[0]
    if err == -2: # gaierror
    print(TAG+"Name or service not known. Exiting function")
    return
    elif err == 116:
    print(TAG+"NTP timed out. Exiting function.")
    return
    else:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    @@ -823,7 +827,7 @@ def send_to_pushingbox():
    response = network.fetch(s) # Get the spreadsheet partly
    except OSError as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing

  7. PaulskPt revised this gist Apr 3, 2024. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -821,7 +821,7 @@ def send_to_pushingbox():
    print(TAG+"Data Sent")
    try:
    response = network.fetch(s) # Get the spreadsheet partly
    except (OSError) as e:
    except OSError as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    2 changes: 1 addition & 1 deletion code_using_aio.py
    Original file line number Diff line number Diff line change
    @@ -517,7 +517,7 @@ def send_to_pushingbox():

    try:
    response = network.fetch(s) # Get the spreadsheet partly
    except (OSError) as e:
    except OSError as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
  8. PaulskPt revised this gist Apr 3, 2024. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion code_using_aio.py
    Original file line number Diff line number Diff line change
    @@ -515,7 +515,13 @@ def send_to_pushingbox():
    print("\"", end='\n') # To complete the message to the Serial (REPL) window
    print(TAG+"Data Sent")

    response = network.fetch(s) # Get the spreadsheet partly
    try:
    response = network.fetch(s) # Get the spreadsheet partly
    except (OSError) as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing

    if response:
    le = len(response.text)
  9. PaulskPt revised this gist Apr 3, 2024. 1 changed file with 20 additions and 8 deletions.
    28 changes: 20 additions & 8 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -94,12 +94,18 @@
    blu_tpl = (0, 0, b2)
    blk_tpl = (0,0,0)

    RED = 0
    YLW = 1
    GRN = 2
    BLU = 3
    BLK = 4

    clr_dict = {
    0 : "RED",
    1 : "YLW",
    2 : "GRN",
    3 : "BLU",
    4 : "BLK"
    RED : "RED",
    YLW : "YLW",
    GRN : "GRN",
    BLU : "BLU",
    BLK : "BLK"
    }
    button_colors = (red_tpl, ylw_tpl, grn_tpl, blu_tpl, blk_tpl) # last tuple added for color black
    button_tones = (1047, 1318, 1568, 2093, 440)
    @@ -624,7 +630,7 @@ def set_INT_RTC():
    s2 = "datetime stamp: "
    dt = None
    internal_RTC = True if is_INT_RTC() else False

    if internal_RTC:
    try:
    dt = ntp.datetime
    @@ -634,7 +640,7 @@ def set_INT_RTC():
    except OSError as e:
    if e.args[0] == 116:
    print(TAG+"NTP timed out. Exiting function.")
    return
    return
    else:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    @@ -813,8 +819,14 @@ def send_to_pushingbox():
    print("\n\""+s, end='')
    print("\"", end='\n') # To complete the message to the Serial (REPL) window
    print(TAG+"Data Sent")
    try:
    response = network.fetch(s) # Get the spreadsheet partly
    except (OSError) as e:
    print(TAG+f"Error: {e}")
    if e.args[0] == -2: # gaierror
    # See: https://docs.circuitpython.org/_/downloads/en/6.3.x/pdf/, page 216
    return # do nothing

    response = network.fetch(s) # Get the spreadsheet partly
    if my_debug:
    print()
    print(TAG+f"response= {response}")
  10. PaulskPt revised this gist Apr 3, 2024. 2 changed files with 20 additions and 30 deletions.
    24 changes: 5 additions & 19 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -88,24 +88,18 @@
    b2=15 # idem 150
    b3=18 # idem 180

    RED = 0
    YLW = 1
    GRN = 2
    BLU = 3
    BLK = 4

    red_tpl = (b2, 0, 0)
    ylw_tpl = (b1, b2, 0)
    grn_tpl = (0, b2, 0)
    blu_tpl = (0, 0, b2)
    blk_tpl = (0,0,0)

    clr_dict = {
    RED : "RED",
    YLW : "YLW",
    GRN : "GRN",
    BLU : "BLU",
    BLK : "BLK"
    0 : "RED",
    1 : "YLW",
    2 : "GRN",
    3 : "BLU",
    4 : "BLK"
    }
    button_colors = (red_tpl, ylw_tpl, grn_tpl, blu_tpl, blk_tpl) # last tuple added for color black
    button_tones = (1047, 1318, 1568, 2093, 440)
    @@ -123,14 +117,6 @@
    tmp_cl = None
    hum_cl = None

    """
    tm_year = 0
    tm_mon = 1
    tm_mday = 2
    tm_hour = 3
    tm_min = 4
    tm_sec = 5
    """
    tm_wday = 6
    tm_yday = 7
    tm_isdst = 8
    26 changes: 15 additions & 11 deletions code_using_aio.py
    Original file line number Diff line number Diff line change
    @@ -80,18 +80,18 @@
    b2=15 # idem 150
    b3=18 # idem 180

    RED = 0
    YLW = 1
    GRN = 2
    BLU = 3
    BLK = 4

    red_tpl = (b2, 0, 0)
    ylw_tpl = (b1, b2, 0)
    grn_tpl = (0, b2, 0)
    blu_tpl = (0, 0, b2)
    blk_tpl = (0,0,0)

    RED = 0
    YLW = 1
    GRN = 2
    BLU = 3
    BLK = 4

    clr_dict = {
    RED : "RED",
    YLW : "YLW",
    @@ -433,7 +433,6 @@ def pr_th_msg():

    ret = True


    upd_dt = tmp_cl.last_upd # [:10] # e.g.: 2022-08-10T16:40:16Z

    # -----------------
    @@ -712,6 +711,7 @@ def main():
    global curr_tm, use_sound, use_leds, wait_for_zero_sec, my_debug, interval
    TAG = 'main(): '
    setup()
    curr_tm = time.time() # set curr_tm for the first time
    start = True
    msg_sent = False
    delay = 3
    @@ -721,6 +721,7 @@ def main():
    toml_zero_sec = 0
    toml_debug = 1
    wifi_cnt = 0
    doit = False
    while True:
    try:
    while not wifi_is_connected():
    @@ -757,7 +758,6 @@ def main():

    if not rtc_set:
    get_time_fm_aio()
    curr_tm = time.time() # set curr_tm for the first time

    if rtc_set:
    ct = time.time() # rtc_bi.datetime
    @@ -772,9 +772,13 @@ def main():
    msg_sent = False
    # print(TAG+f"ct= {ct}, curr_tm= {curr_tm}. Difference= {ct - curr_tm} secs.")
    # print(TAG+f"c_diff % {dt1}= {c1}. c_diff % {dt2}= {c2}. Looping...")
    print(TAG+"c_diff % {:3d}= {:4d}. c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # if start or (not sensor) or (c1 >= (dt1 - 10) and c1 <= dt1) and (not msg_sent): # 5 min interval (give some space)
    if start or (not sensor) or (c2 >= (dt2 - 10) and c2 <= dt2) and (not msg_sent): # 5 min interval (give some space)
    print(TAG+"c_diff % {:3d}= {:4d}, c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # doit = True if (c2 == dt2) else False
    if c2 == 0:
    doit = True
    else:
    doit = False
    if start or (not sensor) or (doit) and (not msg_sent):
    start = False
    blink_leds() # switch off LEDs
    get_th_direct() # sensor directly connected to MAGTAG board via I2C/Stemma_QT
  11. PaulskPt revised this gist Apr 3, 2024. 1 changed file with 36 additions and 23 deletions.
    59 changes: 36 additions & 23 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -375,8 +375,8 @@ def setup():
    if not my_debug:
    print(TAG + "We have an internal RTC")
    print(TAG + "Going to set internal RTC")
    set_INT_RTC()
    dummy = is_dst( time.localtime(time.time()) )
    # set_INT_RTC()
    if SYS_RTC_is_set:
    if my_debug:
    print(TAG + "and the internal RTC is set from an NTP server")
    @@ -441,19 +441,17 @@ def is_NTP():
    TAG = "is_NTP(): "
    global NTP_dt_is_set, NTP_dt, ntp
    ret = False
    dt = None
    try:
    if ntp is not None:
    if not NTP_dt_is_set:
    if my_debug:
    print(TAG+f"type(ntp)= {type(ntp)}")
    print(TAG+f"ntp.datetime= {ntp.datetime}")
    dt = ntp.datetime
    NTP_dt = dt
    NTP_dt = ntp.datetime
    if my_debug:
    print(TAG + f"NTP_dt: {NTP_dt}")
    NTP_dt_is_set = True
    ret = True if dt is not None else False
    ret = True if NTP_dt is not None else False
    except OSError as e:
    print(f"is_NTP() error: {e}")
    return ret
    @@ -481,21 +479,26 @@ def is_NTP():
    * @return Boolean
    """
    def is_dst(tm):
    global ntp, dst_offset
    global ntp, dst_offset, NTP_dt
    TAG = "is_dst(): "

    if not my_debug:
    print(TAG+f"param tm= {tm}")

    yy = tm.tm_year

    dst_org = dst_offset # get original value

    if not tm.tm_year in dst.keys():
    if not yy in dst.keys():
    print(
    TAG
    + f"year: {tm.tm_year} not in dst dictionary {dst.keys()}.\nUpdate the dictionary! Exiting..."
    + f"year: {yy} not in dst dictionary {dst.keys()}.\nUpdate the dictionary! Exiting..."
    )
    raise SystemExit
    #raise SystemExit
    else:
    dst_start_end = dst[tm.tm_year]
    dst_start_end = dst[yy]
    if not my_debug:
    print(TAG + f"year: {tm.tm_year}, dst_start_end: {dst_start_end}")
    print(TAG + f"year: {yy}, dst_start_end: {dst_start_end}")
    cur_dt = time.localtime()
    dst_start1 = dst_start_end[0]
    dst_end1 = dst_start_end[1]
    @@ -635,17 +638,22 @@ def set_INT_RTC():
    s2 = "datetime stamp: "
    dt = None
    internal_RTC = True if is_INT_RTC() else False

    if internal_RTC:
    try:
    dt = ntp.datetime
    if not rtc_set:
    rtc_bi.datetime = dt
    rtc_set = True
    except OSError as e:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    )
    raise
    if e.args[0] == 116:
    print(TAG+"NTP timed out. Exiting function.")
    return
    else:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    )
    raise
    except Exception as e:
    raise

    @@ -1028,6 +1036,7 @@ def main():
    toml_zero_sec = 0
    toml_debug = 1
    wifi_cnt = 0
    doit = False
    while True:
    try:
    while not wifi_is_connected():
    @@ -1073,15 +1082,20 @@ def main():
    dt2 = interval # default: 3600 seconds = 1 hour
    c1 = c_diff % dt1
    c2 = c_diff % dt2

    # print(TAG+"c1: {:4d}, dt1: {:4d}, c1 % 10 = {:2d}. c1 == dt1: {:s}".format(c1, dt1, c1 % 10, "True" if (c1 == dt1) else "False"))
    # print(TAG+"c2: {:4d}, dt2: {:4d}, c2 % 10 = {:2d}. c2 == dt2: {:s}".format(c2, dt2, c2 % 10, "True" if (c1 == dt1) else "False"))
    if c1 % 10 == 0:
    if msg_sent:
    msg_sent = False
    # print(TAG+f"ct= {ct}, curr_tm= {curr_tm}. Difference= {ct - curr_tm} secs.")
    # print(TAG+f"c_diff % {dt1}= {c1}. c_diff % {dt2}= {c2}. Looping...")
    print(TAG+"c_diff % {:3d}= {:4d}. c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # if start or (not sensor) or (c1 >= (dt1 - 10) and c1 <= dt1) and (not msg_sent): # 5 min interval (give some space)
    if start or (not sensor) or (c2 >= (dt2 - 10) and c2 <= dt2) and (not msg_sent): # 5 min interval (give some space)
    print(TAG+"c_diff % {:3d}= {:4d}, c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # doit = True if (c2 == dt2) else False
    if c2 == 0:
    doit = True
    else:
    doit = False
    if start or (not sensor) or (doit) and (not msg_sent):
    start = False
    blink_leds() # switch off LEDs
    get_th_direct() # sensor directly connected to MAGTAG board via I2C/Stemma_QT
    @@ -1090,10 +1104,9 @@ def main():
    raise KeyboardInterrupt
    else:
    msg_sent = True
    #if c2 == 30:
    # sys.exit() # Temporary forced end of execution

    if c2 >= (dt2 - 10) and c2 <= dt2: # 1 hour interval (give some space)
    # if c2 == 30:
    # sys.exit() # Temporary forced end of execution
    if doit:
    set_INT_RTC() # get_time_fm_aio()
    curr_tm = ct
    time.sleep(1)
  12. PaulskPt revised this gist Apr 1, 2024. 1 changed file with 409 additions and 0 deletions.
    409 changes: 409 additions & 0 deletions REPL_example2_output.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,409 @@
    Monday 2024-04-01 00h18 utc+1

    Board: MAGTAG


    soft reboot

    Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
    code.py output:
    is_usb(): Are we connected to USB? Yes
    setup(): Interval set for 3600 seconds
    setup(): Display height= 127, width= 295
    setup(): Connecting to AP ____________
    setup(): Ping google.com: 0.013 ms
    setup(): We have NTP
    setup(): We have an internal RTC
    setup(): Going to set internal RTC
    is_dst(): dst_start_end: (1711846800, 1729994400)
    is_dst(): dst_org 0, dst_new: 1. We are going to set the ntp object with timezone offset: 1 hour(s)
    set_INT_RTC(): Internal (SYS) RTC is set from NTP service datetime stamp:
    set_INT_RTC(): 4/01/2024
    set_INT_RTC(): 00:18:26 weekday: Monday
    set_INT_RTC(): Note that NTP weekday starts with 0
    is_dst(): Are we in daylight saving time for country: 'PRT', state: '' ? Yes
    is_dst(): Days to start of daylight saving time period: -1
    is_dst(): Days to end of daylight saving time period: 209

    Status of global flags: (set in file settings.toml):
    pr_flags(): sound : Yes
    pr_flags(): LEDs : Yes
    pr_flags(): start at zero sec: No
    pr_flags(): print debug : No

    dt_fm_rtc(): dts= 2024-04-01T00:18:41Z
    Connecting to AP ______________
    Retrieving data...
    send_to_pushingbox(): response.status_code= 200 (= OK)
    main(): c_diff % 600= 30. c_diff % 3600= 30. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 40. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 50. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 60. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 70. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 80. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 90. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 100. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 110. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 120. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 130. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 140. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 150. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 160. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 170. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 180. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 190. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 200. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 210. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 220. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 230. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 240. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 250. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 260. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 270. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 280. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 290. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 300. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 310. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 320. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 330. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 340. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 350. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 360. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 370. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 380. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 390. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 400. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 410. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 420. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 430. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 440. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 450. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 460. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 470. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 480. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 490. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 500. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 510. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 520. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 530. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 540. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 550. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 560. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 570. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 580. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 590. Looping...
    main(): c_diff % 600= 0. c_diff % 3600= 600. Looping...
    main(): c_diff % 600= 10. c_diff % 3600= 610. Looping...
    main(): c_diff % 600= 20. c_diff % 3600= 620. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 630. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 640. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 650. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 660. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 670. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 680. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 690. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 700. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 710. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 720. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 730. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 740. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 750. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 760. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 770. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 780. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 790. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 800. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 810. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 820. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 830. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 840. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 850. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 860. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 870. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 880. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 890. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 900. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 910. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 920. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 930. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 940. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 950. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 960. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 970. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 980. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 990. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 1000. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 1010. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 1020. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 1030. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 1040. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 1050. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 1060. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 1070. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 1080. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 1090. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 1100. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 1110. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 1120. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 1130. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 1140. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 1150. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 1160. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 1170. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 1180. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 1190. Looping...
    main(): c_diff % 600= 0. c_diff % 3600= 1200. Looping...
    main(): c_diff % 600= 10. c_diff % 3600= 1210. Looping...
    main(): c_diff % 600= 20. c_diff % 3600= 1220. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 1230. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 1240. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 1250. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 1260. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 1270. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 1280. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 1290. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 1300. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 1310. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 1320. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 1330. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 1340. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 1350. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 1360. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 1370. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 1380. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 1390. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 1400. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 1410. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 1420. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 1430. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 1440. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 1450. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 1460. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 1470. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 1480. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 1490. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 1500. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 1510. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 1520. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 1530. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 1540. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 1550. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 1560. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 1570. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 1580. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 1590. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 1600. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 1610. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 1620. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 1630. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 1640. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 1650. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 1660. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 1670. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 1680. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 1690. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 1700. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 1710. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 1720. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 1730. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 1740. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 1750. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 1760. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 1770. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 1780. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 1790. Looping...
    main(): c_diff % 600= 0. c_diff % 3600= 1800. Looping...
    main(): c_diff % 600= 10. c_diff % 3600= 1810. Looping...
    main(): c_diff % 600= 20. c_diff % 3600= 1820. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 1830. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 1840. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 1850. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 1860. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 1870. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 1880. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 1890. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 1900. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 1910. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 1920. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 1930. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 1940. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 1950. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 1960. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 1970. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 1980. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 1990. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 2000. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 2010. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 2020. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 2030. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 2040. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 2050. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 2060. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 2070. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 2080. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 2090. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 2100. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 2110. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 2120. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 2130. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 2140. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 2150. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 2160. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 2170. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 2180. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 2190. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 2200. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 2210. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 2220. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 2230. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 2240. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 2250. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 2260. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 2270. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 2280. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 2290. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 2300. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 2310. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 2320. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 2330. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 2340. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 2350. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 2360. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 2370. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 2380. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 2390. Looping...
    main(): c_diff % 600= 0. c_diff % 3600= 2400. Looping...
    main(): c_diff % 600= 10. c_diff % 3600= 2410. Looping...
    main(): c_diff % 600= 20. c_diff % 3600= 2420. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 2430. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 2440. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 2450. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 2460. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 2470. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 2480. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 2490. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 2500. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 2510. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 2520. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 2530. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 2540. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 2550. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 2560. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 2570. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 2580. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 2590. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 2600. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 2610. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 2620. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 2630. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 2640. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 2650. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 2660. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 2670. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 2680. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 2690. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 2700. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 2710. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 2720. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 2730. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 2740. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 2750. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 2760. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 2770. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 2780. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 2790. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 2800. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 2810. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 2820. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 2830. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 2840. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 2850. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 2860. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 2870. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 2880. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 2890. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 2900. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 2910. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 2920. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 2930. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 2940. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 2950. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 2960. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 2970. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 2980. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 2990. Looping...
    main(): c_diff % 600= 0. c_diff % 3600= 3000. Looping...
    main(): c_diff % 600= 10. c_diff % 3600= 3010. Looping...
    main(): c_diff % 600= 20. c_diff % 3600= 3020. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 3030. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 3040. Looping...
    main(): c_diff % 600= 50. c_diff % 3600= 3050. Looping...
    main(): c_diff % 600= 60. c_diff % 3600= 3060. Looping...
    main(): c_diff % 600= 70. c_diff % 3600= 3070. Looping...
    main(): c_diff % 600= 80. c_diff % 3600= 3080. Looping...
    main(): c_diff % 600= 90. c_diff % 3600= 3090. Looping...
    main(): c_diff % 600= 100. c_diff % 3600= 3100. Looping...
    main(): c_diff % 600= 110. c_diff % 3600= 3110. Looping...
    main(): c_diff % 600= 120. c_diff % 3600= 3120. Looping...
    main(): c_diff % 600= 130. c_diff % 3600= 3130. Looping...
    main(): c_diff % 600= 140. c_diff % 3600= 3140. Looping...
    main(): c_diff % 600= 150. c_diff % 3600= 3150. Looping...
    main(): c_diff % 600= 160. c_diff % 3600= 3160. Looping...
    main(): c_diff % 600= 170. c_diff % 3600= 3170. Looping...
    main(): c_diff % 600= 180. c_diff % 3600= 3180. Looping...
    main(): c_diff % 600= 190. c_diff % 3600= 3190. Looping...
    main(): c_diff % 600= 200. c_diff % 3600= 3200. Looping...
    main(): c_diff % 600= 210. c_diff % 3600= 3210. Looping...
    main(): c_diff % 600= 220. c_diff % 3600= 3220. Looping...
    main(): c_diff % 600= 230. c_diff % 3600= 3230. Looping...
    main(): c_diff % 600= 240. c_diff % 3600= 3240. Looping...
    main(): c_diff % 600= 250. c_diff % 3600= 3250. Looping...
    main(): c_diff % 600= 260. c_diff % 3600= 3260. Looping...
    main(): c_diff % 600= 270. c_diff % 3600= 3270. Looping...
    main(): c_diff % 600= 280. c_diff % 3600= 3280. Looping...
    main(): c_diff % 600= 290. c_diff % 3600= 3290. Looping...
    main(): c_diff % 600= 300. c_diff % 3600= 3300. Looping...
    main(): c_diff % 600= 310. c_diff % 3600= 3310. Looping...
    main(): c_diff % 600= 320. c_diff % 3600= 3320. Looping...
    main(): c_diff % 600= 330. c_diff % 3600= 3330. Looping...
    main(): c_diff % 600= 340. c_diff % 3600= 3340. Looping...
    main(): c_diff % 600= 350. c_diff % 3600= 3350. Looping...
    main(): c_diff % 600= 360. c_diff % 3600= 3360. Looping...
    main(): c_diff % 600= 370. c_diff % 3600= 3370. Looping...
    main(): c_diff % 600= 380. c_diff % 3600= 3380. Looping...
    main(): c_diff % 600= 390. c_diff % 3600= 3390. Looping...
    main(): c_diff % 600= 400. c_diff % 3600= 3400. Looping...
    main(): c_diff % 600= 410. c_diff % 3600= 3410. Looping...
    main(): c_diff % 600= 420. c_diff % 3600= 3420. Looping...
    main(): c_diff % 600= 430. c_diff % 3600= 3430. Looping...
    main(): c_diff % 600= 440. c_diff % 3600= 3440. Looping...
    main(): c_diff % 600= 450. c_diff % 3600= 3450. Looping...
    main(): c_diff % 600= 460. c_diff % 3600= 3460. Looping...
    main(): c_diff % 600= 470. c_diff % 3600= 3470. Looping...
    main(): c_diff % 600= 480. c_diff % 3600= 3480. Looping...
    main(): c_diff % 600= 490. c_diff % 3600= 3490. Looping...
    main(): c_diff % 600= 500. c_diff % 3600= 3500. Looping...
    main(): c_diff % 600= 510. c_diff % 3600= 3510. Looping...
    main(): c_diff % 600= 520. c_diff % 3600= 3520. Looping...
    main(): c_diff % 600= 530. c_diff % 3600= 3530. Looping...
    main(): c_diff % 600= 540. c_diff % 3600= 3540. Looping...
    main(): c_diff % 600= 550. c_diff % 3600= 3550. Looping...
    main(): c_diff % 600= 560. c_diff % 3600= 3560. Looping...
    main(): c_diff % 600= 570. c_diff % 3600= 3570. Looping...
    main(): c_diff % 600= 580. c_diff % 3600= 3580. Looping...
    main(): c_diff % 600= 590. c_diff % 3600= 3590. Looping...
    dt_fm_rtc(): dts= 2024-04-01T01:18:16Z
    Retrieving data...
    send_to_pushingbox(): response.status_code= 200 (= OK)
    set_INT_RTC(): Internal (SYS) RTC is set from NTP service datetime stamp:
    set_INT_RTC(): 4/01/2024
    set_INT_RTC(): 01:18:26 weekday: Monday
    set_INT_RTC(): Note that NTP weekday starts with 0
    main(): c_diff % 600= 20. c_diff % 3600= 20. Looping...
    main(): c_diff % 600= 30. c_diff % 3600= 30. Looping...
    main(): c_diff % 600= 40. c_diff % 3600= 40. Looping...

    [...]

    Etcetera...

  13. PaulskPt revised this gist Apr 1, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.txt
    Original file line number Diff line number Diff line change
    @@ -11,5 +11,5 @@ There are 2 examples of code.py in this DataToGoogle_MAGTAG Gist:
    For this script, beside the modules used in example 1), we need also the modules:
    socketpool;
    adafruit_ntp;
    and my own module: dst_prt (see below in this Gist.
    and my own module: dst_prt (see below in this Gist).

  14. PaulskPt revised this gist Apr 1, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.txt
    Original file line number Diff line number Diff line change
    @@ -11,5 +11,5 @@ There are 2 examples of code.py in this DataToGoogle_MAGTAG Gist:
    For this script, beside the modules used in example 1), we need also the modules:
    socketpool;
    adafruit_ntp;
    and my own module: dst_prt
    and my own module: dst_prt (see below in this Gist.

  15. PaulskPt revised this gist Apr 1, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.txt
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    There are 2 examples of code.py:
    There are 2 examples of code.py in this DataToGoogle_MAGTAG Gist:
    1) The CircuitPython script, "code_using_aio.py" (rename it to "code.py"), uses the following CircuitPython (V9) library files:
    - adafruit_bitmap_font;
    - adafruit_io;
  16. PaulskPt revised this gist Apr 1, 2024. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -372,11 +372,11 @@ def setup():
    if not my_debug:
    print(TAG + "We have NTP")
    if is_INT_RTC():
    dummy = is_dst( time.localtime(time.time()) )
    if not my_debug:
    print(TAG + "We have an internal RTC")
    print(TAG + "Going to set internal RTC")
    set_INT_RTC()
    dummy = is_dst( time.localtime(time.time()) )
    # set_INT_RTC()
    if SYS_RTC_is_set:
    if my_debug:
    print(TAG + "and the internal RTC is set from an NTP server")
    @@ -495,7 +495,7 @@ def is_dst(tm):
    else:
    dst_start_end = dst[tm.tm_year]
    if not my_debug:
    print(TAG + f"dst_start_end: {dst_start_end}")
    print(TAG + f"year: {tm.tm_year}, dst_start_end: {dst_start_end}")
    cur_dt = time.localtime()
    dst_start1 = dst_start_end[0]
    dst_end1 = dst_start_end[1]
    @@ -549,6 +549,7 @@ def is_dst(tm):

    if dst_new != dst_org:
    dst_offset = dst_new
    print(TAG+f"dst_org {dst_org}, dst_new: {dst_new}. We are going to set the ntp object with timezone offset: {TZ_OFFSET if dst_offset else 0} hour(s)")
    ntp = adafruit_ntp.NTP(pool, tz_offset=TZ_OFFSET if dst_offset else 0)
    set_INT_RTC()

    @@ -596,7 +597,7 @@ def dt_fm_rtc():
    dt = time.localtime()
    dts = "{:d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec)
    if not my_debug:
    print(TAG+f"dts= {dts}, dt.tm_isdst= {dt.tm_isdst}")
    print(TAG+f"dts= {dts}") #, dt.tm_isdst= {dt.tm_isdst}")
    return dts


  17. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -372,8 +372,7 @@ def setup():
    if not my_debug:
    print(TAG + "We have NTP")
    if is_INT_RTC():
    dtg_start = True # Set flag to call disp_dt()
    # dummy = is_dst( time.localtime(time.time()) )
    dummy = is_dst( time.localtime(time.time()) )
    if not my_debug:
    print(TAG + "We have an internal RTC")
    print(TAG + "Going to set internal RTC")
    @@ -559,7 +558,7 @@ def is_dst(tm):
    s = "Yes" if dst_offset == 1 else "No"
    print(
    TAG
    + f"Are we in daylight saving time for country: '{COUNTRY}', '{STATE}' ? {s}"
    + f"Are we in daylight saving time for country: '{COUNTRY}', state: '{STATE}' ? {s}"
    )

    myDate = Date()
  18. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions settings.toml
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,9 @@ CIRCUITPY_WIFI_PASSWORD="<Your PASSWORD"
    ADAFRUIT_IO_USERNAME = "<Your Adafruit IO Username>" # Not needed for example 2
    ADAFRUIT_IO_KEY = "<Your Adafruit IO Key>" # Not needed for example 2
    timezone= "Europe/Lisbon" # http://worldtimeapi.org/timezones
    TZ_OFFSET= "1" # Hours
    COUNTRY="PRT"
    STATE=""
    PUSHING_BOX_DEVID= "<Your Pushingbox.com DEVID>"
    MY_DEBUG = "1"
    USE_LEDS = "1"
  19. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 8 additions and 90 deletions.
    98 changes: 8 additions & 90 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -156,6 +156,7 @@
    NTP_dt_is_set = False
    COUNTRY = None
    STATE = None
    dst_offset = 0 # PT wintertime

    class Date:
    def __init__(self):
    @@ -481,7 +482,7 @@ def is_NTP():
    * @return Boolean
    """
    def is_dst(tm):
    global ntp
    global ntp, dst_offset
    TAG = "is_dst(): "

    dst_org = dst_offset # get original value
    @@ -550,6 +551,7 @@ def is_dst(tm):
    if dst_new != dst_org:
    dst_offset = dst_new
    ntp = adafruit_ntp.NTP(pool, tz_offset=TZ_OFFSET if dst_offset else 0)
    set_INT_RTC()

    ret = True if dst_offset == 1 else False
    if not my_debug:
    @@ -593,12 +595,9 @@ def is_dst(tm):
    def dt_fm_rtc():
    TAG = "dt_fm_rtc(): "
    dt = time.localtime()
    tm_dst = is_dst(dt) # was: -1
    # tm_dst_s = "Yes" if tm_dst == 1 else "No "
    dt.tm_isdst = 1 if tm_dst else 0
    dts = "{:d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec)
    if not my_debug:
    print(TAG+f"dts= {}, dt.tm_isdst= {dt.tm_isdst}")
    print(TAG+f"dts= {dts}, dt.tm_isdst= {dt.tm_isdst}")
    return dts


    @@ -687,89 +686,6 @@ def set_INT_RTC():
    print(TAG + "Note that NTP weekday starts with 0")


    def get_time_fm_aio():
    global rtc_set, curr_tm, dts, TZ_OFFSET
    TAG = "get_time_fm_aio(): "
    network = magtag.network
    TIME_URL = "https://io.adafruit.com/api/v2/{:s}/integrations/".format(os.getenv("ADAFRUIT_IO_USERNAME"))
    TIME_URL += "time/strftime?x-aio-key={:s}".format(os.getenv("ADAFRUIT_IO_KEY"))
    TIME_URL += "&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z"
    print(TAG+"Fetching date and time from: \"{}...\"".format(TIME_URL[:31])) # don't print aio_username neither aio_key

    try:
    response = network.fetch(TIME_URL)
    except (ConnectionError, ValueError, RuntimeError) as e:
    print(TAG+f"Error: {e}. Restarting in 3 seconds...")
    # Exit program and restart in 3 seconds.
    magtag.exit_and_deep_sleep(3)

    if my_debug and response is not None:
    print()
    print("-" * 40)
    print(TAG+f"response.text= {response.text}")
    print("-" * 40)
    if response:
    if not rtc_set:
    curr_date = response.text[:10]
    curr_time = response.text[11:19]
    print(f"curr_date: {curr_date}, curr_time: {curr_time}")
    # tm = time.struct_time

    tz = response.text[30:40]
    if my_debug:
    print(TAG+"tz= \"{}\"".format(tz))
    resp_lst = response.text.split(" ") # response split = ['2022-03-13', '17:02:51.303', '072', '7', '+0000', 'WET']
    if resp_lst[5] == 'WEST':
    dst = 1
    elif resp_lst[5] == 'WET':
    dst = 0
    else:
    dst = -1
    if my_debug:
    print(TAG+"dst=", dst)
    print(TAG+"response.text.split=", resp_lst)
    dt = response.text[:10]
    # tm = response.text[11:16] # 23]
    hh = int(resp_lst[1][:2])
    mm = int(resp_lst[1][3:5]) # +mm_corr # add the correction
    ss = int(resp_lst[1][6:8])
    yd = int(resp_lst[2]) # day of the year
    wd = int(resp_lst[3])-1 # day of the week -- strftime %u (weekday base Monday = 1), so correct because CPY datetime uses base 0
    # sDt = "Day of the year: {}, {} {} {} {} {}".format(yd, weekdays[wd], resp_lst[0], resp_lst[1][:5], resp_lst[4], resp_lst[5])

    # Set the internal RTC
    yy = int(dt[:4])
    mo = int(dt[5:7])
    dd = int(dt[8:10])
    tm2 = (yy, mo, dd, hh, mm, ss, wd, yd, dst)
    tm3 = time.struct_time(tm2)
    if my_debug:
    print(TAG+"dt=",dt)
    print(TAG+"yy ={}, mo={}, dd={}".format(yy, mm, dd))
    print(TAG+"tm2=",tm2)
    print(TAG+"tm3=",tm3)

    rtc_bi.datetime = tm3 # set the built-in RTC

    if wait_for_zero_sec: # see flag at start of this func
    print(TAG+"Waiting for time.localtime seconds reaching 0 ...")
    while True:
    t = time.localtime()
    if t[5] == 0: # Wait until seconds is almost 60 (0)
    # print("t[tm_sec]=", t[5])
    break
    print(TAG+f"finished waiting for zero second")
    curr_tm = time.time() # get the time in seconds since epoch (set curr_tm only at startup)
    rtc_set = True

    # Prepare datetime for funct get_th_direct()
    # format: 2022-08-10T16:40:16Z
    dts = dt[:4] + "-" + dt[5:7] + "-" + dt[8:10] + "T" + resp_lst[1][:2] + ":" + resp_lst[1][3:5] + ":" + resp_lst[1][6:8] + "Z"


    response.close() # Free resources (like socket) - to be used elsewhere


    def get_th_direct():
    global t_dict, h_dict, curr_tm, tmp_old, hum_old, tmp_cl, hum_cl, sensor
    # datetime e.g.: 2022-08-10T16:40:16Z
    @@ -905,7 +821,9 @@ def send_to_pushingbox():
    print(TAG+"Data Sent")

    response = network.fetch(s) # Get the spreadsheet partly

    if my_debug:
    print()
    print(TAG+f"response= {response}")
    if response:
    le = len(response.text)
    if le > 0:
    @@ -1100,6 +1018,7 @@ def main():
    global curr_tm, use_sound, use_leds, wait_for_zero_sec, my_debug, interval
    TAG = 'main(): '
    setup()
    curr_tm = time.time() # set curr_tm for the first time
    start = True
    msg_sent = False
    delay = 3
    @@ -1146,7 +1065,6 @@ def main():
    if not rtc_set:
    set_INT_RTC()
    # get_time_fm_aio()
    curr_tm = time.time() # set curr_tm for the first time

    if rtc_set:
    ct = time.time() # rtc_bi.datetime
  20. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 30 additions and 22 deletions.
    52 changes: 30 additions & 22 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -123,12 +123,14 @@
    tmp_cl = None
    hum_cl = None

    """
    tm_year = 0
    tm_mon = 1
    tm_mday = 2
    tm_hour = 3
    tm_min = 4
    tm_sec = 5
    """
    tm_wday = 6
    tm_yday = 7
    tm_isdst = 8
    @@ -484,14 +486,14 @@ def is_dst(tm):

    dst_org = dst_offset # get original value

    if not tm[tm_year] in dst.keys():
    if not tm.tm_year in dst.keys():
    print(
    TAG
    + f"year: {tm[tm_year]} not in dst dictionary {dst.keys()}.\nUpdate the dictionary! Exiting..."
    + f"year: {tm.tm_year} not in dst dictionary {dst.keys()}.\nUpdate the dictionary! Exiting..."
    )
    raise SystemExit
    else:
    dst_start_end = dst[tm[tm_year]]
    dst_start_end = dst[tm.tm_year]
    if not my_debug:
    print(TAG + f"dst_start_end: {dst_start_end}")
    cur_dt = time.localtime()
    @@ -503,41 +505,41 @@ def is_dst(tm):
    print(
    TAG
    + "dst_start1: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    dst_start2[tm_year],
    dst_start2[tm_mon],
    dst_start2[tm_mday],
    dst_start2[tm_hour],
    dst_start2[tm_min],
    dst_start2[tm_sec],
    dst_start2.tm_year,
    dst_start2.tm_mon,
    dst_start2.tm_mday,
    dst_start2.tm_hour,
    dst_start2.tm_min,
    dst_start2.tm_sec,
    )
    )
    print(
    TAG
    + "current date: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    cur_dt[tm_year],
    cur_dt[tm_mon],
    cur_dt[tm_mday],
    cur_dt[tm_hour],
    cur_dt[tm_min],
    cur_dt[tm_sec],
    cur_dt.tm_year,
    cur_dt.tm_mon,
    cur_dt.tm_mday,
    cur_dt.tm_hour,
    cur_dt.tm_min,
    cur_dt.tm_sec,
    )
    )
    print(
    TAG
    + "dst_end1: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    dst_end2[tm_year],
    dst_end2[tm_mon],
    dst_end2[tm_mday],
    dst_end2[tm_hour],
    dst_end2[tm_min],
    dst_end2[tm_sec],
    dst_end2.tm_year,
    dst_end2.tm_mon,
    dst_end2.tm_mday,
    dst_end2.tm_hour,
    dst_end2.tm_min,
    dst_end2.tm_sec,
    )
    )

    if my_debug:
    print(
    TAG
    + f"year: {tm[tm_year]}, dst start: {dst_start2}, dst end: {dst_end2}"
    + f"year: {tm.tm_year}, dst start: {dst_start2}, dst end: {dst_end2}"
    )
    current_time = time.time()
    if current_time > dst_start1 and current_time < dst_end1:
    @@ -589,8 +591,14 @@ def is_dst(tm):


    def dt_fm_rtc():
    TAG = "dt_fm_rtc(): "
    dt = time.localtime()
    tm_dst = is_dst(dt) # was: -1
    # tm_dst_s = "Yes" if tm_dst == 1 else "No "
    dt.tm_isdst = 1 if tm_dst else 0
    dts = "{:d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec)
    if not my_debug:
    print(TAG+f"dts= {}, dt.tm_isdst= {dt.tm_isdst}")
    return dts


  21. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions README.txt
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    There are 2 versions of code.py:
    There are 2 examples of code.py:
    1) The CircuitPython script, "code_using_aio.py" (rename it to "code.py"), uses the following CircuitPython (V9) library files:
    - adafruit_bitmap_font;
    - adafruit_io;
    @@ -11,6 +11,5 @@ There are 2 versions of code.py:
    For this script, beside the modules used in example 1), we need also the modules:
    socketpool;
    adafruit_ntp;
    and my own module:
    dst_prt
    and my own module: dst_prt

  22. PaulskPt revised this gist Mar 31, 2024. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions dst_PRT.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    # Only used in example 2
    # See: https://www.epochconverter.com/
    # Values are for timezone Europe/Portugal
    dst = {
    2022:(1648342800, 1667095200), # 2022-03-29 01:00:00 / 2022-10-30 02:00:00
    2023:(1679792400, 1698544800), # 2023-03-26 01:00:00 / 2023-10-29 02:00:00
    2024:(1711846800, 1729994400), # 2024-03-31 01:00:00 / 2024-10-27 02:00:00
    2025:(1743296400, 1761444000), # 2025 03-30 01:00:00 / 2025-10-28 02:00:00
    2026:(1774746000, 1792893600), # 2026-03-29 01:00:00 / 2026-10-25 02:00:00
    2027:(1806195600, 1824948000), # 2027-03-28 01:00:00 / 2027-10-31 02:00:00
    2028:(1837645200, 1856397600), # 2028-03-26 01:00:00 / 2028-10-29 02:00:00
    2029:(1869094800, 1887847200), # 2029-03-25 01:00:00 / 2029-10-28 02:00:00
    2030:(1901149200, 1919296800), # 2030-03-31 01:00:00 / 2030-10-27 02:00:00
    2031:(1932598800, 1950746400), # 2031-03-30 01:00:00 / 2031-10-26 02:00:00
    }
  23. PaulskPt revised this gist Mar 31, 2024. 5 changed files with 1193 additions and 4 deletions.
    13 changes: 11 additions & 2 deletions README.txt
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,16 @@
    The CircuitPython script, code.py, uses the following CircuitPython (V9) library files:
    There are 2 versions of code.py:
    1) The CircuitPython script, "code_using_aio.py" (rename it to "code.py"), uses the following CircuitPython (V9) library files:
    - adafruit_bitmap_font;
    - adafruit_io;
    - adafruit_magtag;
    - adafruit_minimqtt;
    - adafruit_ahtx0.mpy;
    - simpleio.mpy.
    - simpleio.mpy.

    2) The CircuitPython script, "code_using_adafruit_ntp.py" (rename it to "code.py").
    For this script, beside the modules used in example 1), we need also the modules:
    socketpool;
    adafruit_ntp;
    and my own module:
    dst_prt

    File renamed without changes.
    1,180 changes: 1,180 additions & 0 deletions code_using_adafruit_ntp.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,1180 @@
    # SPDX-FileCopyrightText: 2020 Brent Rubell, written for Adafruit Industries
    #
    # SPDX-License-Identifier: Unlicense
    #
    # File very modified by @PaulskPt. Latest updates on: 2022-08-11, 2024-03-23
    # (Github @PaulskPt)
    # Last CircuitPython update on: 2024-03-22. Updated CPY to V9.0.0
    # This script has functionality to "hotplug-ing" the sensor.
    # 2024-03-24 15h00 in function send_to_pushingbox() added variable stat_result. If stat == 200, stat_result
    # will show the text "OK" in the top right of the MAGTAG page "latest sensor data". If stat != 200, stat_result
    # will show the text "NO" (meaning: fail).
    # 2024-03-25 13h20 added global variables use_sound and use_leds
    # Button A will toggle sound
    # Button B will toggle LEDs
    # Button C will toggle the global variable wait_for_zero_sec. Then tries to write this setting to file: settings.toml.
    # Button D will toggle the global variable my_debug. Then tries to write this setting to file: settings.toml.
    # Note that file settings.toml can only be updated from within this script when the MAGTAG is not connected to USB.
    # In function send_to_pushingbox() the response is 200 (OK), the LEDs will blink green if use_leds is True.
    # the leds will blink red if the response is other than 200.
    # For module cptoml see: https://github.com/beryllium-org/cptoml
    # When reading the sensor the LEDs of the MAGTAG will blink one time in color Yellow.
    # Depending on the global variable use_sound, a tone will be produced or not.
    # When the datetime stamp and sensor data successfully are sent to Pushingbox.com, the LEDs of the MAGTAG will blink
    # Depending on the global variable use_sound, a tone will be produced or not.
    # one time Green.
    # Added function is_usb() that ckecks if the board is connected to USB or not.
    # Update 2024-03-31
    # Added modules: adafruit_ntp, socketpool and own module dst_prt
    # Deleted function get_time_fm_aio() by set_INT_RTC() which uses adafruit_ntp.
    # From file settings.toml removed "ADAFRUIT_IO_USERNAME" and "ADAFRUIT_IO_KEY"
    """
    The Adafruit MAGTAG contains an ESP32-S2 WROVER chip.
    Note: On 2022-08-10 at 17h12 utc+1 the Google Apps Script system reported that the project
    'DataToGoogle_MAGTAG', deployment version 6, executed successfully.
    This execution came from Pushingbox.com that was triggered by this CircuitPython script (see function 'send_data_to_google()')
    Note also that the Google Apps Script deployment was set that it was available to 'anyone' (with the link).
    On 2024-03-24, in Google Apps Scripts I had to create a new deployment (version 7). It executed successfully.
    """
    import sys
    import os
    import supervisor
    import board
    import time
    import wifi
    import rtc
    import ipaddress
    from adafruit_magtag.magtag import MagTag
    import adafruit_ahtx0
    import socketpool
    import adafruit_ntp
    from dst_PRT import dst

    # Global flags (see setup()):
    use_sound = None
    use_leds = None
    wait_for_zero_sec = None
    my_debug = None
    on_usb = None

    SOUND_IDX = 0
    LEDS_IDX = 1
    ZEROSEC_IDX = 2
    DEBUG_IDX = 3

    TZ_OFFSET = None
    sensor = None
    stat_result = None
    interval = None
    ip = 0

    i2c = board.STEMMA_I2C()

    try:
    sensor = adafruit_ahtx0.AHTx0(i2c)
    except ValueError as e:
    print(f"Global. Error: {e}. Check wiring!")
    pass

    # Create an instance of the MagTag class
    magtag = MagTag()
    height = magtag.graphics.display.height -1
    width = magtag.graphics.display.width -1

    # Less brillance than originally (mod by @paulsk)
    b1=25 # originally 255
    b2=15 # idem 150
    b3=18 # idem 180

    RED = 0
    YLW = 1
    GRN = 2
    BLU = 3
    BLK = 4

    red_tpl = (b2, 0, 0)
    ylw_tpl = (b1, b2, 0)
    grn_tpl = (0, b2, 0)
    blu_tpl = (0, 0, b2)
    blk_tpl = (0,0,0)

    clr_dict = {
    RED : "RED",
    YLW : "YLW",
    GRN : "GRN",
    BLU : "BLU",
    BLK : "BLK"
    }
    button_colors = (red_tpl, ylw_tpl, grn_tpl, blu_tpl, blk_tpl) # last tuple added for color black
    button_tones = (1047, 1318, 1568, 2093, 440)

    msg_sent = 0

    tmp_old = 0.00
    hum_old = 0.00
    upd_dt_old = ""
    dts = "" # Set by get_time_fm_aio() and used in get_th_direct()
    curr_tm = None # struct_time
    rtc_set = False
    rtc_bi = rtc.RTC() # create an instance of the built-in RTC
    weekdays = {0:"Monday", 1:"Tuesday",2:"Wednesday",3:"Thursday",4:"Friday",5:"Saturday",6:"Sunday"}
    tmp_cl = None
    hum_cl = None

    tm_year = 0
    tm_mon = 1
    tm_mday = 2
    tm_hour = 3
    tm_min = 4
    tm_sec = 5
    tm_wday = 6
    tm_yday = 7
    tm_isdst = 8

    rtc_DOW = DOW = {
    0: "Monday",
    1: "Tuesday",
    2: "Wednesday",
    3: "Thursday",
    4: "Friday",
    5: "Saturday",
    6: "Sunday",
    }
    SYS_dt = None
    set_SYS_RTC = True
    SYS_RTC_is_set = False
    TZ_OFFSET = int(os.getenv("TZ_OFFSET"))
    if my_debug:
    print(f"TZ_OFFSET= {TZ_OFFSET}")
    pool = socketpool.SocketPool(wifi.radio)
    ntp = adafruit_ntp.NTP(pool, tz_offset=TZ_OFFSET)
    NTP_dt = None
    NTP_dt_is_set = False
    COUNTRY = None
    STATE = None

    class Date:
    def __init__(self):
    self.d1 = 0 # d
    self.m1 = 0 # m
    self.y1 = 0 # y
    self.d2 = 0 # d
    self.m2 = 0 # m
    self.y2 = 0 # y
    self.monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    # To store number of days in all months from
    # January to Dec.

    # This function counts number of leap years
    # before the given date
    # d = (dd, mo, yy)
    def countLeapYears(self, d):

    years = d[2]

    # Check if the current year needs to be considered
    # for the count of leap years or not
    if (d[1] <= 2):
    years -= 1

    # An year is a leap year if it is a multiple of 4,
    # multiple of 400 and not a multiple of 100.
    return int(years / 4) - int(years / 100) + int(years / 400)


    # This function returns number of days between two
    # given dates
    def getDifference(self, dt1, dt2):
    TAG = "Date.getDifference(): "
    # COUNT TOTAL NUMBER OF DAYS BEFORE FIRST DATE 'dt1'

    for _ in range(2):
    if _ == 0:
    p = dt1
    elif _ == 1:
    p = dt2
    if not isinstance(p, tuple):
    print(TAG+f"Parameter {"dt1" if _ == 0 else "dt2" if _ == 1 else "?"} has to be of type tuple, received type: {type(p)}")

    self.d1 = dt1[0]
    self.m1 = dt1[1]
    self.y1 = dt1[2]

    self.d2 = dt2[0]
    self.m2 = dt2[1]
    self.y2 = dt2[2]

    # initialize count using years and day
    n1 = self.y1 * 365 + self.d1

    # Add days for months in given date
    for i in range(0, self.m1 - 1):
    n1 += self.monthDays[i]

    # Since every leap year is of 366 days,
    # Add a day for every leap year
    n1 += self.countLeapYears(dt1)

    # SIMILARLY, COUNT TOTAL NUMBER OF DAYS BEFORE 'dt2'

    n2 = self.y2 * 365 + self.d2
    for i in range(0, self.m2 - 1):
    n2 += self.monthDays[i]
    n2 += self.countLeapYears(dt2)

    # return difference between two counts
    return (n2 - n1)


    class sensor_tmp:
    def __init__(self, tmp, dt):
    self._tmp = tmp
    self._dt = dt

    @property
    def tmp(self):
    return self._tmp

    @tmp.setter
    def tmp(self, tmp):
    if isinstance(tmp, float):
    self._tmp = tmp
    elif isinstance(tmp, int):
    self._tmp = float(tmp)

    @property
    def last_upd(self):
    return self._dt

    @last_upd.setter
    def last_upd(self, dt):
    if isinstance(dt, str):
    self._dt = dt


    class sensor_hum:
    def __init__(self, hum, dt):
    self._hum = hum
    self._dt = dt

    @property
    def hum(self):
    return self._hum

    @hum.setter
    def hum(self, hum):
    if isinstance(hum, float):
    self._hum = hum
    elif isinstance(hum, int):
    self._hum = float(hum)

    @property
    def last_upd(self):
    return self._dt

    @last_upd.setter
    def last_upd(self, dt):
    if isinstance(dt, str):
    self._dt = dt


    # pylint: disable=no-name-in-module,wrong-import-order

    def setup():
    global tmp_cl, hum_cl, on_usb, use_sound, use_leds, wait_for_zero_sec, my_debug, interval, TZ_OFFSET, COUNTRY, STATE
    TAG = 'setup(): '

    on_usb = is_usb()

    use_sound = True if int(os.getenv("USE_SOUND")) else False
    use_leds = True if int(os.getenv("USE_LEDS")) else False
    wait_for_zero_sec = True if int(os.getenv("WAIT_FOR_ZERO_SEC")) else False
    my_debug = True if int(os.getenv("MY_DEBUG")) else False
    interval = int(os.getenv("INTERVAL_SECONDS"))
    TZ_OFFSET = int(os.getenv("TZ_OFFSET"))
    COUNTRY = os.getenv("COUNTRY")
    STATE = os.getenv("STATE")

    if my_debug:
    print(TAG+f"use_sound= {use_sound}")
    print(TAG+f"use_leds= {use_leds}")
    print(TAG+f"wait_for_zero_sec= {wait_for_zero_sec}")
    print(TAG+f"Interval set for {interval} seconds")

    print(TAG+"Display height= {}, width= {}".format(height, width)) # result: height 127, width 295
    # h0 = height // 6 # 127 // 6 = 21 20 + 21 = 41 , 20 + (2 x 21) = 62, 20 + (3*21)= 83, 20 + (4x21)= 104
    # hlist = [h0, h0*3, h0*5]
    hlist = [20, 41, 62, 83, 104]
    for _ in range (len(hlist)):
    magtag.add_text(
    #text_font="/fonts/Arial-12.pcf",
    text_position=(
    10,
    hlist[_],
    ),
    text_scale=2,
    )


    # Create instances of the sensor_tmp and sensor_hum classes
    tmp_cl = sensor_tmp(0.00, "") # create class instance with default values
    hum_cl = sensor_hum(0.00, "") # same

    text_items = ["Sensor data to Google", "using", "Pushingbox.com", "(c) 2024 @PaulskPt", f"USB connected: {"Yes" if on_usb else "No "}"]
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    try:
    magtag.display.refresh() # refresh the display
    except RuntimeError:
    print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    # +-----------------------------------------------------------+
    # | CONNECT TO WiFi |
    # +-----------------------------------------------------------+
    wifi.AuthMode.WPA2 # set only once
    ssid = os.getenv("CIRCUITPY_WIFI_SSID")
    print(TAG+f"Connecting to AP {os.getenv("CIRCUITPY_WIFI_SSID")}")
    wifi_cnt = 0
    while not wifi_is_connected():
    if not do_connect():
    print(TAG+f"WiFi failed to connect to {ssid}")
    wifi_cnt += 1
    if wifi_cnt >= 5:
    print(TAG+f"tried {wifi_cnt} times to connect WiFi but failed. Exiting...")
    time.sleep(3)
    break

    if wifi_is_connected():
    time.sleep(2)
    ipv4 = ipaddress.ip_address("8.8.8.8")
    ping_time = 0.0
    ping_cnt = 0
    while ping_time is 0.00:
    ping_time = wifi.radio.ping(ipv4)
    if ping_time is None: # prevent crash
    ping_time = 0.0
    if ping_time < 0.001:
    ping_cnt += 1
    if ping_cnt >= 10:
    print(TAG+f"Ping to Google failed. Tried {ping_cnt} times")
    break
    if ping_time > 0.00:
    print(TAG+f"Ping google.com: {ping_time} ms")

    if is_NTP():
    if not my_debug:
    print(TAG + "We have NTP")
    if is_INT_RTC():
    dtg_start = True # Set flag to call disp_dt()
    # dummy = is_dst( time.localtime(time.time()) )
    if not my_debug:
    print(TAG + "We have an internal RTC")
    print(TAG + "Going to set internal RTC")
    set_INT_RTC()
    if SYS_RTC_is_set:
    if my_debug:
    print(TAG + "and the internal RTC is set from an NTP server")


    def blink_and_button_test(clr=None):
    TAG= "blink_test(): "
    if my_debug:
    print(TAG+f"param clr= {clr} = {clr_dict[clr]}")
    cnt = 0
    if clr is None: # Do the test
    while True:
    for i, b in enumerate(magtag.peripherals.buttons):
    if not b.value:
    print("Button %c pressed" % chr((ord("A") + i)))
    magtag.peripherals.neopixel_disable = False
    magtag.peripherals.neopixels.fill(button_colors[i])
    magtag.peripherals.play_tone(button_tones[i], 0.25)
    break
    else:
    magtag.peripherals.neopixels.fill(button_colors[BLK]) # switch neopixels to black (off)
    magtag.peripherals.neopixel_disable = True
    time.sleep(0.01)
    cnt += 1
    if cnt >= len(button_colors):
    print(f"Exiting function: {TAG[:-4]}")
    break

    def blink_leds(clr=BLK):
    if not use_leds:
    return
    TAG= "blink_leds(): "
    if isinstance(clr, int):
    le = len(button_colors)
    if clr < 0:
    clr = 0
    if clr >= le:
    clr = le -1

    if my_debug:
    print(TAG+f"param clr= {clr} = {clr_dict[clr]}")
    magtag.peripherals.neopixel_disable = False
    magtag.peripherals.neopixels.fill(button_colors[clr])
    if use_sound and clr != BLK: # Only sound tone if color is not black
    magtag.peripherals.play_tone(button_tones[clr], 0.25)
    time.sleep(0.01)
    magtag.peripherals.neopixels.fill(button_colors[BLK]) # switch neopixels to black (off)
    magtag.peripherals.neopixel_disable = True


    """
    * @brief This function checks if exists an ntp object
    * If so, it retrieves a datetime stamp from an NTP server
    * and sets NTP_dt to the retrieved datetime stamp
    * It then also sets the NTP_dt_is_set flag
    *
    * @param state
    *
    * @return boolean
    """
    def is_NTP():
    TAG = "is_NTP(): "
    global NTP_dt_is_set, NTP_dt, ntp
    ret = False
    dt = None
    try:
    if ntp is not None:
    if not NTP_dt_is_set:
    if my_debug:
    print(TAG+f"type(ntp)= {type(ntp)}")
    print(TAG+f"ntp.datetime= {ntp.datetime}")
    dt = ntp.datetime
    NTP_dt = dt
    if my_debug:
    print(TAG + f"NTP_dt: {NTP_dt}")
    NTP_dt_is_set = True
    ret = True if dt is not None else False
    except OSError as e:
    print(f"is_NTP() error: {e}")
    return ret

    """
    * @brief This function checks if the passed
    * param tm falls between the limits of
    * 'daylight-saving-time' (dst) of the
    * actual country.
    * This function:
    * - uses the dt dictionary,
    * which has been imported from the file
    * dst_prt.py
    * - If global variable my_debug is True, prints to REPL:
    * - the dst datetime limits to the REPL
    * - nr of days to the start of dst period.
    * - nr of days to the end of dst period.
    * - returns True if the given
    * date is within the dst limits.
    * - returns False if the given
    * date is not within the dst limits.
    *
    * @param tm (a time structure)
    *
    * @return Boolean
    """
    def is_dst(tm):
    global ntp
    TAG = "is_dst(): "

    dst_org = dst_offset # get original value

    if not tm[tm_year] in dst.keys():
    print(
    TAG
    + f"year: {tm[tm_year]} not in dst dictionary {dst.keys()}.\nUpdate the dictionary! Exiting..."
    )
    raise SystemExit
    else:
    dst_start_end = dst[tm[tm_year]]
    if not my_debug:
    print(TAG + f"dst_start_end: {dst_start_end}")
    cur_dt = time.localtime()
    dst_start1 = dst_start_end[0]
    dst_end1 = dst_start_end[1]
    dst_start2 = time.localtime(dst_start1)
    dst_end2 = time.localtime(dst_end1)
    if my_debug:
    print(
    TAG
    + "dst_start1: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    dst_start2[tm_year],
    dst_start2[tm_mon],
    dst_start2[tm_mday],
    dst_start2[tm_hour],
    dst_start2[tm_min],
    dst_start2[tm_sec],
    )
    )
    print(
    TAG
    + "current date: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    cur_dt[tm_year],
    cur_dt[tm_mon],
    cur_dt[tm_mday],
    cur_dt[tm_hour],
    cur_dt[tm_min],
    cur_dt[tm_sec],
    )
    )
    print(
    TAG
    + "dst_end1: {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
    dst_end2[tm_year],
    dst_end2[tm_mon],
    dst_end2[tm_mday],
    dst_end2[tm_hour],
    dst_end2[tm_min],
    dst_end2[tm_sec],
    )
    )

    if my_debug:
    print(
    TAG
    + f"year: {tm[tm_year]}, dst start: {dst_start2}, dst end: {dst_end2}"
    )
    current_time = time.time()
    if current_time > dst_start1 and current_time < dst_end1:
    dst_new = 1
    else:
    dst_new = 0

    if dst_new != dst_org:
    dst_offset = dst_new
    ntp = adafruit_ntp.NTP(pool, tz_offset=TZ_OFFSET if dst_offset else 0)

    ret = True if dst_offset == 1 else False
    if not my_debug:
    # print(TAG+f"dst_offset: {dst_offset}")
    s = "Yes" if dst_offset == 1 else "No"
    print(
    TAG
    + f"Are we in daylight saving time for country: '{COUNTRY}', '{STATE}' ? {s}"
    )

    myDate = Date()

    curr_yr = time.localtime(current_time)[0]
    curr_mon = time.localtime(current_time)[1]
    curr_mday = time.localtime(current_time)[2]
    curr_dt = (curr_mday, curr_mon, curr_yr)

    start_yr = time.localtime(dst_start1)[0]
    start_mon = time.localtime(dst_start1)[1]
    start_mday = time.localtime(dst_start1)[2]
    start_dt = (start_mday, start_mon, start_yr)

    end_yr = time.localtime(dst_end1)[0]
    end_mon = time.localtime(dst_end1)[1]
    end_mday = time.localtime(dst_end1)[2]
    end_dt = (end_mday, end_mon, end_yr)

    if dst_offset:
    days_to_dst_start = myDate.getDifference(curr_dt, start_dt)
    days_to_dst_end = myDate.getDifference(curr_dt, end_dt)
    else:
    days_to_dst_start = myDate.getDifference(curr_dt, start_dt)
    days_to_dst_end = myDate.getDifference(curr_dt, end_dt)

    print(TAG+"Days to start of daylight saving time period: {:3d}".format(days_to_dst_start))
    print(TAG+"Days to end of daylight saving time period: {:3d}".format(days_to_dst_end))

    return ret


    def dt_fm_rtc():
    dt = time.localtime()
    dts = "{:d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec)
    return dts


    """
    * @brief function returns True
    * if RTC object instance mRTC exists
    *
    * @param state
    *
    * @return None
    """
    def is_INT_RTC():
    if rtc_bi is not None:
    return True
    return False


    """
    * @brief This function sets the internal
    * realtime clock
    * It retrieves the datetime stamp from an NTP server
    * on internet
    *
    * @param state
    *
    * @return None
    """
    def set_INT_RTC():
    global rtc_bi, rtc_set, curr_tm, dts
    if not set_SYS_RTC:
    return

    TAG = "set_INT_RTC(): "
    s1 = "Internal (SYS) RTC is set from "
    s2 = "datetime stamp: "
    dt = None
    internal_RTC = True if is_INT_RTC() else False
    if internal_RTC:
    try:
    dt = ntp.datetime
    if not rtc_set:
    rtc_bi.datetime = dt
    rtc_set = True
    except OSError as e:
    print(
    TAG + f"Error while trying to set internal RTC from NTP datetime: {e}"
    )
    raise
    except Exception as e:
    raise

    if wait_for_zero_sec: # see flag at start of this func
    print(TAG+"Waiting for time.localtime seconds reaching 0 ...")
    while True:
    t = time.localtime()
    if t[5] == 0: # Wait until seconds is almost 60 (0)
    # print("t[tm_sec]=", t[5])
    break
    print(TAG+f"finished waiting for zero second")
    curr_tm = time.time() # get the time in seconds since epoch (set curr_tm only at startup)
    rtc_set = True

    # Prepare datetime for funct get_th_direct()
    # format: 2022-08-10T16:40:16Z
    #dts = dt[:4] + "-" + dt[5:7] + "-" + dt[8:10] + "T" + resp_lst[1][:2] + ":" + resp_lst[1][3:5] + ":" + resp_lst[1][6:8] + "Z"
    # dts = dt[:4] + "-" + dt[5:7] + "-" + dt[8:10] + "T" + resp_lst[1][:2] + ":" + resp_lst[1][3:5] + ":" + resp_lst[1][6:8] + "Z"
    dts = "{}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(dt.tm_year, dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec)
    SYS_dt = rtc_bi.datetime
    if my_debug:
    print(TAG + f"rtc_bi.datetime: {rtc_bi.datetime}")
    # print(TAG+f"SYS_dt: {SYS_dt}")
    SYS_RTC_is_set = True
    if SYS_dt.tm_year >= 2000:
    print(TAG + s1 + "NTP service " + s2)

    dt = SYS_dt
    if not my_debug:
    print(TAG + "{:d}/{:02d}/{:02d}".format(dt.tm_mon, dt.tm_mday, dt.tm_year))
    print(
    TAG
    + "{:02d}:{:02d}:{:02d} weekday: {:s}".format(
    dt.tm_hour, dt.tm_min, dt.tm_sec, rtc_DOW[dt.tm_wday]
    )
    )
    if internal_RTC:
    print(TAG + "Note that NTP weekday starts with 0")


    def get_time_fm_aio():
    global rtc_set, curr_tm, dts, TZ_OFFSET
    TAG = "get_time_fm_aio(): "
    network = magtag.network
    TIME_URL = "https://io.adafruit.com/api/v2/{:s}/integrations/".format(os.getenv("ADAFRUIT_IO_USERNAME"))
    TIME_URL += "time/strftime?x-aio-key={:s}".format(os.getenv("ADAFRUIT_IO_KEY"))
    TIME_URL += "&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z"
    print(TAG+"Fetching date and time from: \"{}...\"".format(TIME_URL[:31])) # don't print aio_username neither aio_key

    try:
    response = network.fetch(TIME_URL)
    except (ConnectionError, ValueError, RuntimeError) as e:
    print(TAG+f"Error: {e}. Restarting in 3 seconds...")
    # Exit program and restart in 3 seconds.
    magtag.exit_and_deep_sleep(3)

    if my_debug and response is not None:
    print()
    print("-" * 40)
    print(TAG+f"response.text= {response.text}")
    print("-" * 40)
    if response:
    if not rtc_set:
    curr_date = response.text[:10]
    curr_time = response.text[11:19]
    print(f"curr_date: {curr_date}, curr_time: {curr_time}")
    # tm = time.struct_time

    tz = response.text[30:40]
    if my_debug:
    print(TAG+"tz= \"{}\"".format(tz))
    resp_lst = response.text.split(" ") # response split = ['2022-03-13', '17:02:51.303', '072', '7', '+0000', 'WET']
    if resp_lst[5] == 'WEST':
    dst = 1
    elif resp_lst[5] == 'WET':
    dst = 0
    else:
    dst = -1
    if my_debug:
    print(TAG+"dst=", dst)
    print(TAG+"response.text.split=", resp_lst)
    dt = response.text[:10]
    # tm = response.text[11:16] # 23]
    hh = int(resp_lst[1][:2])
    mm = int(resp_lst[1][3:5]) # +mm_corr # add the correction
    ss = int(resp_lst[1][6:8])
    yd = int(resp_lst[2]) # day of the year
    wd = int(resp_lst[3])-1 # day of the week -- strftime %u (weekday base Monday = 1), so correct because CPY datetime uses base 0
    # sDt = "Day of the year: {}, {} {} {} {} {}".format(yd, weekdays[wd], resp_lst[0], resp_lst[1][:5], resp_lst[4], resp_lst[5])

    # Set the internal RTC
    yy = int(dt[:4])
    mo = int(dt[5:7])
    dd = int(dt[8:10])
    tm2 = (yy, mo, dd, hh, mm, ss, wd, yd, dst)
    tm3 = time.struct_time(tm2)
    if my_debug:
    print(TAG+"dt=",dt)
    print(TAG+"yy ={}, mo={}, dd={}".format(yy, mm, dd))
    print(TAG+"tm2=",tm2)
    print(TAG+"tm3=",tm3)

    rtc_bi.datetime = tm3 # set the built-in RTC

    if wait_for_zero_sec: # see flag at start of this func
    print(TAG+"Waiting for time.localtime seconds reaching 0 ...")
    while True:
    t = time.localtime()
    if t[5] == 0: # Wait until seconds is almost 60 (0)
    # print("t[tm_sec]=", t[5])
    break
    print(TAG+f"finished waiting for zero second")
    curr_tm = time.time() # get the time in seconds since epoch (set curr_tm only at startup)
    rtc_set = True

    # Prepare datetime for funct get_th_direct()
    # format: 2022-08-10T16:40:16Z
    dts = dt[:4] + "-" + dt[5:7] + "-" + dt[8:10] + "T" + resp_lst[1][:2] + ":" + resp_lst[1][3:5] + ":" + resp_lst[1][6:8] + "Z"


    response.close() # Free resources (like socket) - to be used elsewhere


    def get_th_direct():
    global t_dict, h_dict, curr_tm, tmp_old, hum_old, tmp_cl, hum_cl, sensor
    # datetime e.g.: 2022-08-10T16:40:16Z
    TAG = "get_th_direct(): "

    dts = dt_fm_rtc() # get datetime from builtin rtc

    # --------------------------------------------------------------
    if not sensor:
    try:
    sensor = adafruit_ahtx0.AHTx0(i2c)
    except ValueError as e:
    print(TAG+f"Error: {e}. Check wiring!")

    if sensor:
    try:
    tmp = sensor.temperature
    hum = sensor.relative_humidity
    if my_debug:
    blink_leds(YLW)

    tmp_cl.tmp = tmp
    tmp_cl.last_upd = dts

    if tmp != tmp_old:
    tmp_old = tmp
    # ------------------

    hum_cl.hum = hum
    hum_cl.last_upd = dts

    if hum != hum_old:
    hum_old = hum
    # -----------------
    if my_debug:
    print(TAG+f"updated_at: {tmp_cl.last_upd}")
    print(TAG+f"Temperature: {tmp_cl.tmp}")
    print(TAG+f"Humidity: {hum_cl.hum}")

    except ValueError as e:
    print(TAG+f"Error: {e}. Check wiring!")
    pass

    def pr_th_msg():
    global stat_result
    TAG = "pr_th_msg(): "
    if stat_result is None:
    stat_result = ""

    ret = True


    upd_dt = tmp_cl.last_upd # [:10] # e.g.: 2022-08-10T16:40:16Z

    # -----------------
    tmp = tmp_cl.tmp
    tmp_s = str(tmp)
    # -----------------
    hum = hum_cl.hum
    hum_s = str(hum)
    # ----------------

    text_items = ["latest sensor data "+stat_result, "-" * 23, upd_dt, "Temperature: "+tmp_s+" C", "Humidity: "+hum_s+" %"]

    magtag.remove_all_text
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    cnt += 1
    if cnt >= 10:
    ret = False
    break
    except RuntimeError:
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    return ret

    def send_to_pushingbox():
    global msg_sent, upd_dt_old, tmp_old, hum_old, stat_result
    TAG = "send_to_pushingbox(): "
    ret = True
    tmp_s = None
    hum_s = None
    network = magtag.network
    stat_result = None
    devid = os.getenv("PUSHING_BOX_DEVID") # device ID on Pushingbox for our Scenario

    upd_dt = tmp_cl.last_upd # [:10] # e.g.: 2022-08-10T16:40:16Z

    # --------------------------------------------------------------
    tmp = tmp_cl.tmp
    tmp_s = str(tmp)
    if my_debug:
    print(TAG+f"tmp_s= \'{tmp_s}\', tmp_old= {tmp_old}")
    # --------------------------------------------------------------
    hum = hum_cl.hum
    hum_s = str(hum)
    if my_debug:
    print(TAG+f"hum_s= \'{hum_s}\', hum_old= {hum_old}")
    # --------------------------------------------------------------

    # le_old = len(upd_dt_old)
    # if (le_old > 0) and (tmp == tmp_old) and (hum == hum_old): # and upd_dt == upd_dt_old
    if (upd_dt_old == upd_dt) and (tmp == tmp_old) and (hum == hum_old): # and upd_dt == upd_dt_old
    print(TAG+"datetime stamp unchanged. Waiting for new sensor data...")
    return ret # We don't want to send duplicates
    else:
    upd_dt_old = upd_dt #
    #upd_tm = t_dict["updated_at"][11:19]

    msg_sent += 1 # increase the messages sent count
    # dteData = upd_dt # Added 2024-03-22 because this variable was missing.
    # ?date=$date$&time=$time$&temp=$temp$&hum=$hum$

    s = "http://api.pushingbox.com/pushingbox?devid="
    s += devid
    s += "&date=\"" + upd_dt + "\""
    s += "&temp=" + tmp_s
    s += "&hum=" + hum_s

    if my_debug:
    print(TAG+upd_dt, end='')
    print(". Sending Data message nr: ", end='')
    print(msg_sent, end='')
    print(" to middle-man server...", end='\n')
    print(TAG+"Going to send:", end='')
    print("\n\""+s, end='')
    print("\"", end='\n') # To complete the message to the Serial (REPL) window
    print(TAG+"Data Sent")

    response = network.fetch(s) # Get the spreadsheet partly

    if response:
    le = len(response.text)
    if le > 0:
    n = response.text.find("404")
    print(TAG,end='')
    if n >=0:
    print("error 404: file not found on this server.")
    else:
    print(f"response.text[:100]= {response.text[:100]}", end='')
    print(" [...] ", end='')
    print(f"{response.text[-100:]}", end='\n')
    status = response.status_code
    stat_result = "OK" if status == 200 else "NO"
    print()
    s1 = "response.status_code="
    s2 = "{} (= {})".format(status, stat_result)
    print(TAG+f"{s1} {s2}")
    if status == 200:
    blink_leds(GRN)
    else:
    blink_leds(RED)
    if my_debug:
    pr_msg(["send result:", s2])
    response = None
    if my_debug:
    print(TAG+f"upd_dt= {upd_dt}, tmp_s= {tmp_s}, hum_s= {hum_s}")
    pr_th_msg()
    return ret

    def yes_no(nr):
    ret = None
    y = "Yes"
    n = "No "
    if isinstance(nr, int):
    if nr >= 0 and nr <= 3:
    if nr == SOUND_IDX:
    ret = y if use_sound else n
    if nr == LEDS_IDX:
    ret = y if use_leds else n
    if nr == ZEROSEC_IDX:
    ret = y if wait_for_zero_sec else n
    if nr == DEBUG_IDX:
    ret = y if my_debug else n
    return ret

    def pr_buttons():
    text_items = [
    "Btn: Function:",
    "A: sound",
    "B: LEDs",
    "C: wait for zero sec",
    "D: debug texts"]

    pr_msg(text_items)

    def pr_flags():
    TAG= "pr_flags(): "
    itms_lst = ["sound", "LEDs", "start at zero sec", "print debug", ]
    le = len(itms_lst)
    print("\nStatus of global flags: (set in file settings.toml):")
    for _ in range(le):
    print(TAG+"{:17s}: {:s}".format(itms_lst[_], yes_no(_)))
    print()

    text_items = ["global flags "]
    for _ in range(le):
    s = "{:17s}: {:s}".format(itms_lst[_], yes_no(_))
    text_items.append(s)

    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    cnt += 1
    if cnt >= 10:
    break
    except RuntimeError:
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    def is_usb():
    # Test if we're connected to USB
    # If an error occurs we are on USB
    ret = False
    try:
    from storage import remount
    remount("/", False)
    except (RuntimeError) as e:
    ret = True

    print(f"is_usb(): Are we connected to USB? {"Yes" if ret else "No"}")
    return ret

    def do_connect():
    global ip
    TAG = "do_connect(): "
    ret = False
    # Get env variables from file settings.toml
    ssid = os.getenv("CIRCUITPY_WIFI_SSID")
    pw = os.getenv("CIRCUITPY_WIFI_PASSWORD")
    s__ip = ""
    try:
    wifi.radio.connect(ssid=ssid, password=pw)
    except ConnectionError as e:
    print(TAG+f"WiFi connection Error: \'{e}\'")
    except Exception as e:
    print(TAG+f"Error: {dir(e)}")

    ip = wifi.radio.ipv4_address

    if ip:
    s__ip = str(ip)
    ret = True
    if my_debug:
    print(TAG+f"connected to \'{ssid}\'. IP: {s__ip}")
    return ret

    def wifi_is_connected():
    global ip
    s__ip = str(ip)
    return True if s__ip is not None and len(s__ip) > 0 and s__ip != '0.0.0.0' else False

    def pr_msg(msg):
    text_items = []
    le_max = 5
    if isinstance(msg, list):
    le_msg = len(msg)
    if le_msg > 0 and le_msg <= le_max:
    for _ in range(len(msg)):
    text_items.append(msg[_])
    le = len(text_items)
    if le_max - le > 0: # fill up with blank lines
    for _ in range(le_max - le):
    text_items.append(" ")
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    cnt += 1
    if cnt >= 10:
    break
    except RuntimeError:
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    def wr_to_toml(itm):
    TAG= "wr_to_toml(): "
    toml_f = "settings.toml"
    if on_usb:
    s1 = "Writing to file"
    s2 = "works only when"
    s3 = "not connected to USB"
    print(TAG+f"{s1}{toml_f} {s2} {s3}")
    pr_msg([s1, toml_f, s2, s3])
    pr_th_msg() # rewrite the temperature & humidity page
    return False

    ret = True
    delay = 3
    itms = [("WAIT_FOR_ZERO_SEC", wait_for_zero_sec), ("MY_DEBUG", my_debug)]

    print(TAG+f"param rcvd: itm= {itm}")

    itm_s = itms[itm][0]
    val = itms[itm][1]
    val_s = "1" if val == True else "0"
    print(TAG+f"Trying to write to file: {toml_f}, item: \"{itm_s}\" with value: {val_s}")
    # Write
    try:
    from cptoml import put
    from storage import remount
    remount("/", False)
    #put("CIRCUITPY_PYSTACK_SIZE", 7000) # To set an item in root table
    put(itm_s, val_s) #, "subtable1", comment="This is useless") # To set item1 in subtable1 with comment
    remount("/", True)
    pr_msg([itm_s, "value: " + val_s, "successfully", "written to:", toml_f])
    print("Software reset in %d seconds" % delay)
    time.sleep(delay)
    supervisor.reload()
    except (RuntimeError, ImportError, OSError) as e:
    print(TAG+f"Error: {e}")
    ret = False
    return ret

    def main():
    global curr_tm, use_sound, use_leds, wait_for_zero_sec, my_debug, interval
    TAG = 'main(): '
    setup()
    start = True
    msg_sent = False
    delay = 3
    # blink_and_button_test() # Test the Magtag LEDs
    pr_buttons()
    pr_flags()
    toml_zero_sec = 0
    toml_debug = 1
    wifi_cnt = 0
    while True:
    try:
    while not wifi_is_connected():
    if do_connect():
    break
    else:
    wifi_cnt += 1
    if wifi_cnt >= 5:
    print(TAG+f"WiFi connection failed. Tried {wifi_cnt} times")
    raise RuntimeError

    if magtag.peripherals.button_a_pressed:
    use_sound = not use_sound # toggle sound
    s1 = "button A pressed."
    s2 = "sound {:s}".format(yes_no(SOUND_IDX))
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_b_pressed:
    use_leds = not use_leds # toggle leds
    s1 = "button B pressed."
    s2 = "LEDs {:s}".format(yes_no(LEDS_IDX))
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_c_pressed:
    wait_for_zero_sec = not wait_for_zero_sec
    print(TAG+"button C pressed. Start time wait for zero seconds {:s}".format(yes_no(ZEROSEC_IDX)))
    wr_to_toml(toml_zero_sec)
    if magtag.peripherals.button_d_pressed:
    my_debug = not my_debug
    print(TAG+"button d pressed. Debug print statements {:s}".format(yes_no(DEBUG_IDX)))
    wr_to_toml(toml_debug)

    if not rtc_set:
    set_INT_RTC()
    # get_time_fm_aio()
    curr_tm = time.time() # set curr_tm for the first time

    if rtc_set:
    ct = time.time() # rtc_bi.datetime
    c_diff = ct - curr_tm
    dt1 = interval // 6 # default: 3600 seconds. 3600 // 6 = 600 seconds = 10 minutes. See setup().
    dt2 = interval # default: 3600 seconds = 1 hour
    c1 = c_diff % dt1
    c2 = c_diff % dt2

    if c1 % 10 == 0:
    if msg_sent:
    msg_sent = False
    # print(TAG+f"ct= {ct}, curr_tm= {curr_tm}. Difference= {ct - curr_tm} secs.")
    # print(TAG+f"c_diff % {dt1}= {c1}. c_diff % {dt2}= {c2}. Looping...")
    print(TAG+"c_diff % {:3d}= {:4d}. c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # if start or (not sensor) or (c1 >= (dt1 - 10) and c1 <= dt1) and (not msg_sent): # 5 min interval (give some space)
    if start or (not sensor) or (c2 >= (dt2 - 10) and c2 <= dt2) and (not msg_sent): # 5 min interval (give some space)
    start = False
    blink_leds() # switch off LEDs
    get_th_direct() # sensor directly connected to MAGTAG board via I2C/Stemma_QT

    if not send_to_pushingbox():
    raise KeyboardInterrupt
    else:
    msg_sent = True
    #if c2 == 30:
    # sys.exit() # Temporary forced end of execution

    if c2 >= (dt2 - 10) and c2 <= dt2: # 1 hour interval (give some space)
    set_INT_RTC() # get_time_fm_aio()
    curr_tm = ct
    time.sleep(1)
    except ImportError: # e.g.: no module named 'platform' (in file :/lib/Adafruit_IO/Client.py, line 24)
    pass
    except KeyboardInterrupt:
    raise SystemExit

    if __name__ == '__main__':
    main()
    File renamed without changes.
    4 changes: 2 additions & 2 deletions settings.toml
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    CIRCUITPY_WIFI_SSID="<Your SSID>"
    CIRCUITPY_WIFI_PASSWORD="<Your PASSWORD"
    ADAFRUIT_IO_USERNAME = "<Your Adafruit IO Username>"
    ADAFRUIT_IO_KEY = "<Your Adafruit IO Key>"
    ADAFRUIT_IO_USERNAME = "<Your Adafruit IO Username>" # Not needed for example 2
    ADAFRUIT_IO_KEY = "<Your Adafruit IO Key>" # Not needed for example 2
    timezone= "Europe/Lisbon" # http://worldtimeapi.org/timezones
    PUSHING_BOX_DEVID= "<Your Pushingbox.com DEVID>"
    MY_DEBUG = "1"
  24. PaulskPt revised this gist Mar 26, 2024. 1 changed file with 85 additions and 16 deletions.
    101 changes: 85 additions & 16 deletions code.py
    Original file line number Diff line number Diff line change
    @@ -60,6 +60,7 @@
    sensor = None
    stat_result = None
    interval = None
    ip = 0

    i2c = board.STEMMA_I2C()

    @@ -180,7 +181,7 @@ def setup():
    my_debug = True if int(os.getenv("MY_DEBUG")) else False
    interval = int(os.getenv("INTERVAL_SECONDS"))

    if not my_debug:
    if my_debug:
    print(TAG+f"use_sound= {use_sound}")
    print(TAG+f"use_leds= {use_leds}")
    print(TAG+f"wait_for_zero_sec= {wait_for_zero_sec}")
    @@ -214,16 +215,38 @@ def setup():
    print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    print(TAG+f"Connecting to AP {os.getenv("CIRCUITPY_WIFI_SSID")}")
    # +-----------------------------------------------------------+
    # | CONNECT TO WiFi |
    # +-----------------------------------------------------------+
    wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
    time.sleep(2)
    ipv4 = ipaddress.ip_address("8.8.8.8")
    print(TAG+f"Connected to {os.getenv("CIRCUITPY_WIFI_SSID")}")
    print(TAG+f"My IP address is {wifi.radio.ipv4_address}")
    print(TAG+f"Ping google.com: {wifi.radio.ping(ipv4)} ms")
    wifi.AuthMode.WPA2 # set only once
    ssid = os.getenv("CIRCUITPY_WIFI_SSID")
    print(TAG+f"Connecting to AP {os.getenv("CIRCUITPY_WIFI_SSID")}")
    wifi_cnt = 0
    while not wifi_is_connected():
    if not do_connect():
    print(TAG+f"WiFi failed to connect to {ssid}")
    wifi_cnt += 1
    if wifi_cnt >= 5:
    print(TAG+f"tried {wifi_cnt} times to connect WiFi but failed. Exiting...")
    time.sleep(3)
    break

    if wifi_is_connected():
    time.sleep(2)
    ipv4 = ipaddress.ip_address("8.8.8.8")
    ping_time = 0.0
    ping_cnt = 0
    while ping_time is 0.00:
    ping_time = wifi.radio.ping(ipv4)
    if ping_time is None: # prevent crash
    ping_time = 0.0
    if ping_time < 0.001:
    ping_cnt += 1
    if ping_cnt >= 10:
    print(TAG+f"Ping to Google failed. Tried {ping_cnt} times")
    break
    if ping_time > 0.00:
    print(TAG+f"Ping google.com: {ping_time} ms")


    def blink_and_button_test(clr=None):
    @@ -285,8 +308,14 @@ def get_time_fm_aio():
    TIME_URL += "&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z"
    print(TAG+"Fetching date and time from: \"{}...\"".format(TIME_URL[:31])) # don't print aio_username neither aio_key

    response = network.fetch(TIME_URL)
    if not my_debug and response is not None:
    try:
    response = network.fetch(TIME_URL)
    except (ConnectionError, ValueError, RuntimeError) as e:
    print(TAG+f"Error: {e}. Restarting in 3 seconds...")
    # Exit program and restart in 3 seconds.
    magtag.exit_and_deep_sleep(3)

    if my_debug and response is not None:
    print()
    print("-" * 40)
    print(TAG+f"response.text= {response.text}")
    @@ -308,7 +337,7 @@ def get_time_fm_aio():
    dst = 0
    else:
    dst = -1
    if not my_debug:
    if my_debug:
    print(TAG+"dst=", dst)
    print(TAG+"response.text.split=", resp_lst)
    dt = response.text[:10]
    @@ -387,7 +416,7 @@ def get_th_direct():
    if hum != hum_old:
    hum_old = hum
    # -----------------
    if not my_debug:
    if my_debug:
    print(TAG+f"updated_at: {tmp_cl.last_upd}")
    print(TAG+f"Temperature: {tmp_cl.tmp}")
    print(TAG+f"Humidity: {hum_cl.hum}")
    @@ -449,12 +478,12 @@ def send_to_pushingbox():
    # --------------------------------------------------------------
    tmp = tmp_cl.tmp
    tmp_s = str(tmp)
    if not my_debug:
    if my_debug:
    print(TAG+f"tmp_s= \'{tmp_s}\', tmp_old= {tmp_old}")
    # --------------------------------------------------------------
    hum = hum_cl.hum
    hum_s = str(hum)
    if not my_debug:
    if my_debug:
    print(TAG+f"hum_s= \'{hum_s}\', hum_old= {hum_old}")
    # --------------------------------------------------------------

    @@ -477,7 +506,7 @@ def send_to_pushingbox():
    s += "&temp=" + tmp_s
    s += "&hum=" + hum_s

    if not my_debug:
    if my_debug:
    print(TAG+upd_dt, end='')
    print(". Sending Data message nr: ", end='')
    print(msg_sent, end='')
    @@ -510,7 +539,8 @@ def send_to_pushingbox():
    blink_leds(GRN)
    else:
    blink_leds(RED)
    pr_msg(["send result:", s2])
    if my_debug:
    pr_msg(["send result:", s2])
    response = None
    if my_debug:
    print(TAG+f"upd_dt= {upd_dt}, tmp_s= {tmp_s}, hum_s= {hum_s}")
    @@ -584,6 +614,35 @@ def is_usb():
    print(f"is_usb(): Are we connected to USB? {"Yes" if ret else "No"}")
    return ret

    def do_connect():
    global ip
    TAG = "do_connect(): "
    ret = False
    # Get env variables from file settings.toml
    ssid = os.getenv("CIRCUITPY_WIFI_SSID")
    pw = os.getenv("CIRCUITPY_WIFI_PASSWORD")
    s__ip = ""
    try:
    wifi.radio.connect(ssid=ssid, password=pw)
    except ConnectionError as e:
    print(TAG+f"WiFi connection Error: \'{e}\'")
    except Exception as e:
    print(TAG+f"Error: {dir(e)}")

    ip = wifi.radio.ipv4_address

    if ip:
    s__ip = str(ip)
    ret = True
    if my_debug:
    print(TAG+f"connected to \'{ssid}\'. IP: {s__ip}")
    return ret

    def wifi_is_connected():
    global ip
    s__ip = str(ip)
    return True if s__ip is not None and len(s__ip) > 0 and s__ip != '0.0.0.0' else False

    def pr_msg(msg):
    text_items = []
    le_max = 5
    @@ -661,8 +720,18 @@ def main():
    pr_flags()
    toml_zero_sec = 0
    toml_debug = 1
    wifi_cnt = 0
    while True:
    try:
    while not wifi_is_connected():
    if do_connect():
    break
    else:
    wifi_cnt += 1
    if wifi_cnt >= 5:
    print(TAG+f"WiFi connection failed. Tried {wifi_cnt} times")
    raise RuntimeError

    if magtag.peripherals.button_a_pressed:
    use_sound = not use_sound # toggle sound
    s1 = "button A pressed."
  25. PaulskPt revised this gist Mar 26, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion code.py
    Original file line number Diff line number Diff line change
    @@ -683,7 +683,7 @@ def main():
    wr_to_toml(toml_zero_sec)
    if magtag.peripherals.button_d_pressed:
    my_debug = not my_debug
    print(TAG+"button d pressed. Switching debug print statements {:s}".format(yes_no(DEBUG_IDX)))
    print(TAG+"button d pressed. Debug print statements {:s}".format(yes_no(DEBUG_IDX)))
    wr_to_toml(toml_debug)

    if not rtc_set:
  26. PaulskPt revised this gist Mar 25, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions code.py
    Original file line number Diff line number Diff line change
    @@ -679,11 +679,11 @@ def main():
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_c_pressed:
    wait_for_zero_sec = not wait_for_zero_sec
    print(TAG+f"button C pressed. Start time wait for zero seconds {"on" if wait_for_zero_sec else "off"}")
    print(TAG+"button C pressed. Start time wait for zero seconds {:s}".format(yes_no(ZEROSEC_IDX)))
    wr_to_toml(toml_zero_sec)
    if magtag.peripherals.button_d_pressed:
    my_debug = not my_debug
    print(TAG+f"button d pressed. Switching debug print statements {"on" if my_debug else "off"}")
    print(TAG+"button d pressed. Switching debug print statements {:s}".format(yes_no(DEBUG_IDX)))
    wr_to_toml(toml_debug)

    if not rtc_set:
  27. PaulskPt revised this gist Mar 25, 2024. 2 changed files with 24 additions and 15 deletions.
    36 changes: 22 additions & 14 deletions code.py
    Original file line number Diff line number Diff line change
    @@ -46,14 +46,20 @@
    import adafruit_ahtx0

    # Global flags (see setup()):
    my_debug = None
    use_sound = None
    use_leds = None
    wait_for_zero_sec = None
    on_usb = None
    my_debug = None
    on_usb = None

    SOUND_IDX = 0
    LEDS_IDX = 1
    ZEROSEC_IDX = 2
    DEBUG_IDX = 3

    sensor = None
    stat_result = None
    interval = None

    i2c = board.STEMMA_I2C()

    @@ -163,19 +169,22 @@ def last_upd(self, dt):
    # pylint: disable=no-name-in-module,wrong-import-order

    def setup():
    global tmp_cl, hum_cl, on_usb, my_debug, use_sound, use_leds, wait_for_zero_sec
    global tmp_cl, hum_cl, on_usb, use_sound, use_leds, wait_for_zero_sec, my_debug, interval
    TAG = 'setup(): '

    on_usb = is_usb()

    my_debug = True if int(os.getenv("MY_DEBUG")) else False
    use_sound = True if int(os.getenv("USE_SOUND")) else False
    use_leds = True if int(os.getenv("USE_LEDS")) else False
    wait_for_zero_sec = True if int(os.getenv("WAIT_FOR_ZERO_SEC")) else False
    my_debug = True if int(os.getenv("MY_DEBUG")) else False
    interval = int(os.getenv("INTERVAL_SECONDS"))

    if not my_debug:
    print(TAG+f"use_sound= {use_sound}")
    print(TAG+f"use_leds= {use_leds}")
    print(TAG+f"wait_for_zero_sec= {wait_for_zero_sec}")
    print(TAG+f"Interval set for {interval} seconds")

    print(TAG+"Display height= {}, width= {}".format(height, width)) # result: height 127, width 295
    # h0 = height // 6 # 127 // 6 = 21 20 + 21 = 41 , 20 + (2 x 21) = 62, 20 + (3*21)= 83, 20 + (4x21)= 104
    @@ -514,13 +523,13 @@ def yes_no(nr):
    n = "No "
    if isinstance(nr, int):
    if nr >= 0 and nr <= 3:
    if nr == 0:
    if nr == SOUND_IDX:
    ret = y if use_sound else n
    if nr == 1:
    if nr == LEDS_IDX:
    ret = y if use_leds else n
    if nr == 2:
    if nr == ZEROSEC_IDX:
    ret = y if wait_for_zero_sec else n
    if nr == 3:
    if nr == DEBUG_IDX:
    ret = y if my_debug else n
    return ret

    @@ -641,11 +650,10 @@ def wr_to_toml(itm):
    return ret

    def main():
    global curr_tm, my_debug, use_sound, use_leds, wait_for_zero_sec
    global curr_tm, use_sound, use_leds, wait_for_zero_sec, my_debug, interval
    TAG = 'main(): '
    setup()
    start = True
    interval = 600 # 10 minutes
    msg_sent = False
    delay = 3
    # blink_and_button_test() # Test the Magtag LEDs
    @@ -658,14 +666,14 @@ def main():
    if magtag.peripherals.button_a_pressed:
    use_sound = not use_sound # toggle sound
    s1 = "button A pressed."
    s2 = f"Switching sound {"on" if use_sound else "off"}"
    s2 = "sound {:s}".format(yes_no(SOUND_IDX))
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_b_pressed:
    use_leds = not use_leds # toggle leds
    s1 = "button B pressed."
    s2 = f"Switching LEDs {"on" if use_leds else "off"}"
    s2 = "LEDs {:s}".format(yes_no(LEDS_IDX))
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    @@ -685,8 +693,8 @@ def main():
    if rtc_set:
    ct = time.time() # rtc_bi.datetime
    c_diff = ct - curr_tm
    dt1 = interval # see above
    dt2 = dt1 * 6 # = 6 x 600 = 3600 seconds = 1 hour
    dt1 = interval // 6 # default: 3600 seconds. 3600 // 6 = 600 seconds = 10 minutes. See setup().
    dt2 = interval # default: 3600 seconds = 1 hour
    c1 = c_diff % dt1
    c2 = c_diff % dt2

    3 changes: 2 additions & 1 deletion settings.toml
    Original file line number Diff line number Diff line change
    @@ -7,4 +7,5 @@ PUSHING_BOX_DEVID= "<Your Pushingbox.com DEVID>"
    MY_DEBUG = "1"
    USE_LEDS = "1"
    USE_SOUND = "1"
    WAIT_FOR_ZERO_SEC = "1"
    WAIT_FOR_ZERO_SEC = "1" # line-up time
    INTERVAL_SECONDS = "3600" # 1 hour - set for a multiple of 60
  28. PaulskPt revised this gist Mar 25, 2024. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion settings.toml
    Original file line number Diff line number Diff line change
    @@ -3,4 +3,8 @@ CIRCUITPY_WIFI_PASSWORD="<Your PASSWORD"
    ADAFRUIT_IO_USERNAME = "<Your Adafruit IO Username>"
    ADAFRUIT_IO_KEY = "<Your Adafruit IO Key>"
    timezone= "Europe/Lisbon" # http://worldtimeapi.org/timezones
    PUSHING_BOX_DEVID= "<Your Pushingbox.com DEVID>"
    PUSHING_BOX_DEVID= "<Your Pushingbox.com DEVID>"
    MY_DEBUG = "1"
    USE_LEDS = "1"
    USE_SOUND = "1"
    WAIT_FOR_ZERO_SEC = "1"
  29. PaulskPt revised this gist Mar 25, 2024. 1 changed file with 237 additions and 33 deletions.
    270 changes: 237 additions & 33 deletions code.py
    Original file line number Diff line number Diff line change
    @@ -12,8 +12,18 @@
    # 2024-03-25 13h20 added global variables use_sound and use_leds
    # Button A will toggle sound
    # Button B will toggle LEDs
    # in function send_to_pushingbox() the response is 200 (OK), the LEDs will blink green if use_leds is True.
    # Button C will toggle the global variable wait_for_zero_sec. Then tries to write this setting to file: settings.toml.
    # Button D will toggle the global variable my_debug. Then tries to write this setting to file: settings.toml.
    # Note that file settings.toml can only be updated from within this script when the MAGTAG is not connected to USB.
    # In function send_to_pushingbox() the response is 200 (OK), the LEDs will blink green if use_leds is True.
    # the leds will blink red if the response is other than 200.
    # For module cptoml see: https://github.com/beryllium-org/cptoml
    # When reading the sensor the LEDs of the MAGTAG will blink one time in color Yellow.
    # Depending on the global variable use_sound, a tone will be produced or not.
    # When the datetime stamp and sensor data successfully are sent to Pushingbox.com, the LEDs of the MAGTAG will blink
    # Depending on the global variable use_sound, a tone will be produced or not.
    # one time Green.
    # Added function is_usb() that ckecks if the board is connected to USB or not.
    """
    The Adafruit MAGTAG contains an ESP32-S2 WROVER chip.
    @@ -24,8 +34,9 @@
    On 2024-03-24, in Google Apps Scripts I had to create a new deployment (version 7). It executed successfully.
    """
    #import sys
    import sys
    import os
    import supervisor
    import board
    import time
    import wifi
    @@ -34,11 +45,15 @@
    from adafruit_magtag.magtag import MagTag
    import adafruit_ahtx0

    my_debug = False
    use_sound = True
    use_leds = True
    # Global flags (see setup()):
    my_debug = None
    use_sound = None
    use_leds = None
    wait_for_zero_sec = None
    on_usb = None

    sensor = None
    stat_result = None

    i2c = board.STEMMA_I2C()

    @@ -148,9 +163,20 @@ def last_upd(self, dt):
    # pylint: disable=no-name-in-module,wrong-import-order

    def setup():
    global tmp_cl, hum_cl
    global tmp_cl, hum_cl, on_usb, my_debug, use_sound, use_leds, wait_for_zero_sec
    TAG = 'setup(): '

    on_usb = is_usb()

    my_debug = True if int(os.getenv("MY_DEBUG")) else False
    use_sound = True if int(os.getenv("USE_SOUND")) else False
    use_leds = True if int(os.getenv("USE_LEDS")) else False
    wait_for_zero_sec = True if int(os.getenv("WAIT_FOR_ZERO_SEC")) else False
    if not my_debug:
    print(TAG+f"use_sound= {use_sound}")
    print(TAG+f"use_leds= {use_leds}")
    print(TAG+f"wait_for_zero_sec= {wait_for_zero_sec}")

    print(TAG+"Display height= {}, width= {}".format(height, width)) # result: height 127, width 295
    # h0 = height // 6 # 127 // 6 = 21 20 + 21 = 41 , 20 + (2 x 21) = 62, 20 + (3*21)= 83, 20 + (4x21)= 104
    # hlist = [h0, h0*3, h0*5]
    @@ -169,7 +195,7 @@ def setup():
    tmp_cl = sensor_tmp(0.00, "") # create class instance with default values
    hum_cl = sensor_hum(0.00, "") # same

    text_items = ["Sensor data to Google", "using", "Pushingbox.com", "(c) 2024 @PaulskPt"]
    text_items = ["Sensor data to Google", "using", "Pushingbox.com", "(c) 2024 @PaulskPt", f"USB connected: {"Yes" if on_usb else "No "}"]
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    @@ -226,7 +252,7 @@ def blink_leds(clr=BLK):
    clr = le -1

    if my_debug:
    print(TAG+f"param clr (modified)= {clr} = {clr_dict[clr]}")
    print(TAG+f"param clr= {clr} = {clr_dict[clr]}")
    magtag.peripherals.neopixel_disable = False
    magtag.peripherals.neopixels.fill(button_colors[clr])
    if use_sound and clr != BLK: # Only sound tone if color is not black
    @@ -245,7 +271,6 @@ def get_time_fm_aio():
    global rtc_set, curr_tm, dts
    TAG = "get_time_fm_aio(): "
    network = magtag.network
    wait_for_zero_sec = False
    TIME_URL = "https://io.adafruit.com/api/v2/{:s}/integrations/".format(os.getenv("ADAFRUIT_IO_USERNAME"))
    TIME_URL += "time/strftime?x-aio-key={:s}".format(os.getenv("ADAFRUIT_IO_KEY"))
    TIME_URL += "&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z"
    @@ -299,15 +324,15 @@ def get_time_fm_aio():
    print(TAG+"tm3=",tm3)

    rtc_bi.datetime = tm3 # set the built-in RTC
    print(TAG+"Waiting for time.localtime seconds reaching 0 ...")

    if wait_for_zero_sec: # see flag at start of this func
    print(TAG+"Waiting for time.localtime seconds reaching 0 ...")
    while True:
    t = time.localtime()
    if t[5] >= 56: # Wait until seconds is almost 60 (0)
    if t[5] == 0: # Wait until seconds is almost 60 (0)
    # print("t[tm_sec]=", t[5])
    break

    print(TAG+f"finished waiting for zero second")
    curr_tm = time.time() # get the time in seconds since epoch (set curr_tm only at startup)
    rtc_set = True

    @@ -345,14 +370,14 @@ def get_th_direct():

    if tmp != tmp_old:
    tmp_old = tmp
    # --------------------------------------------------------------
    # ------------------

    hum_cl.hum = hum
    hum_cl.last_upd = dts

    if hum != hum_old:
    hum_old = hum
    # --------------------------------------------------------------
    # -----------------
    if not my_debug:
    print(TAG+f"updated_at: {tmp_cl.last_upd}")
    print(TAG+f"Temperature: {tmp_cl.tmp}")
    @@ -362,9 +387,46 @@ def get_th_direct():
    print(TAG+f"Error: {e}. Check wiring!")
    pass

    def pr_th_msg():
    global stat_result
    TAG = "pr_th_msg(): "
    if stat_result is None:
    stat_result = ""

    ret = True


    upd_dt = tmp_cl.last_upd # [:10] # e.g.: 2022-08-10T16:40:16Z

    # -----------------
    tmp = tmp_cl.tmp
    tmp_s = str(tmp)
    # -----------------
    hum = hum_cl.hum
    hum_s = str(hum)
    # ----------------

    text_items = ["latest sensor data "+stat_result, "-" * 23, upd_dt, "Temperature: "+tmp_s+" C", "Humidity: "+hum_s+" %"]

    magtag.remove_all_text
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    cnt += 1
    if cnt >= 10:
    ret = False
    break
    except RuntimeError:
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    return ret

    def send_to_pushingbox():
    global msg_sent, upd_dt_old, tmp_old, hum_old
    global msg_sent, upd_dt_old, tmp_old, hum_old, stat_result
    TAG = "send_to_pushingbox(): "
    ret = True
    tmp_s = None
    @@ -430,50 +492,192 @@ def send_to_pushingbox():
    print(" [...] ", end='')
    print(f"{response.text[-100:]}", end='\n')
    status = response.status_code
    print()
    print(TAG+"response.status_code=", status, "(= OK)" if status == 200 else "")
    stat_result = "OK" if status == 200 else "NO"
    print()
    s1 = "response.status_code="
    s2 = "{} (= {})".format(status, stat_result)
    print(TAG+f"{s1} {s2}")
    if status == 200:
    blink_leds(GRN)
    else:
    blink_leds(RED)
    pr_msg(["send result:", s2])
    response = None
    if my_debug:
    print(TAG+f"upd_dt= {upd_dt}, tmp_s= {tmp_s}, hum_s= {hum_s}")
    text_items = ["latest sensor data "+stat_result, "-" * 23, upd_dt, "Temperature: "+tmp_s+" C", "Humidity: "+hum_s+" %"]
    magtag.remove_all_text
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    pr_th_msg()
    return ret

    def yes_no(nr):
    ret = None
    y = "Yes"
    n = "No "
    if isinstance(nr, int):
    if nr >= 0 and nr <= 3:
    if nr == 0:
    ret = y if use_sound else n
    if nr == 1:
    ret = y if use_leds else n
    if nr == 2:
    ret = y if wait_for_zero_sec else n
    if nr == 3:
    ret = y if my_debug else n
    return ret

    def pr_buttons():
    text_items = [
    "Btn: Function:",
    "A: sound",
    "B: LEDs",
    "C: wait for zero sec",
    "D: debug texts"]

    pr_msg(text_items)

    def pr_flags():
    TAG= "pr_flags(): "
    itms_lst = ["sound", "LEDs", "start at zero sec", "print debug", ]
    le = len(itms_lst)
    print("\nStatus of global flags: (set in file settings.toml):")
    for _ in range(le):
    print(TAG+"{:17s}: {:s}".format(itms_lst[_], yes_no(_)))
    print()

    text_items = ["global flags state:"]
    for _ in range(le):
    s = "{:17s}: {:s}".format(itms_lst[_], yes_no(_))
    text_items.append(s)

    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    #time.sleep(3)
    cnt += 1
    if cnt >= 10:
    break
    except RuntimeError:
    print(TAG+"RuntimeError...MAGTAG refresh too soon")
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon
    except KeyboardInterrupt:
    ret = False

    def is_usb():
    # Test if we're connected to USB
    # If an error occurs we are on USB
    ret = False
    try:
    from storage import remount
    remount("/", False)
    except (RuntimeError) as e:
    ret = True

    print(f"is_usb(): Are we connected to USB? {"Yes" if ret else "No"}")
    return ret

    def pr_msg(msg):
    text_items = []
    le_max = 5
    if isinstance(msg, list):
    le_msg = len(msg)
    if le_msg > 0 and le_msg <= le_max:
    for _ in range(len(msg)):
    text_items.append(msg[_])
    le = len(text_items)
    if le_max - le > 0: # fill up with blank lines
    for _ in range(le_max - le):
    text_items.append(" ")
    for i in range(len(text_items)):
    magtag.set_text(text_items[i], i, auto_refresh = False) # Display the dt, tm and tz
    time.sleep(1) # to prevent RuntimeError Refresh too soon
    cnt = 0
    while True:
    try:
    magtag.display.refresh() # refresh the display
    cnt += 1
    if cnt >= 10:
    break
    except RuntimeError:
    # print(TAG+"RuntimeError")
    pass # reason: Refresh too soon

    def wr_to_toml(itm):
    TAG= "wr_to_toml(): "
    toml_f = "settings.toml"
    if on_usb:
    s1 = "Writing to file"
    s2 = "works only when"
    s3 = "not connected to USB"
    print(TAG+f"{s1}{toml_f} {s2} {s3}")
    pr_msg([s1, toml_f, s2, s3])
    pr_th_msg() # rewrite the temperature & humidity page
    return False

    ret = True
    delay = 3
    itms = [("WAIT_FOR_ZERO_SEC", wait_for_zero_sec), ("MY_DEBUG", my_debug)]

    print(TAG+f"param rcvd: itm= {itm}")

    itm_s = itms[itm][0]
    val = itms[itm][1]
    val_s = "1" if val == True else "0"
    print(TAG+f"Trying to write to file: {toml_f}, item: \"{itm_s}\" with value: {val_s}")
    # Write
    try:
    from cptoml import put
    from storage import remount
    remount("/", False)
    #put("CIRCUITPY_PYSTACK_SIZE", 7000) # To set an item in root table
    put(itm_s, val_s) #, "subtable1", comment="This is useless") # To set item1 in subtable1 with comment
    remount("/", True)
    pr_msg([itm_s, "value: " + val_s, "successfully", "written to:", toml_f])
    print("Software reset in %d seconds" % delay)
    time.sleep(delay)
    supervisor.reload()
    except (RuntimeError, ImportError, OSError) as e:
    print(TAG+f"Error: {e}")
    ret = False
    return ret

    def main():
    global curr_tm, use_sound, use_leds
    global curr_tm, my_debug, use_sound, use_leds, wait_for_zero_sec
    TAG = 'main(): '
    setup()
    start = True
    interval = 120 # 0 # 10 minutes
    interval = 600 # 10 minutes
    msg_sent = False
    delay = 3
    # blink_and_button_test() # Test the Magtag LEDs
    pr_buttons()
    pr_flags()
    toml_zero_sec = 0
    toml_debug = 1
    while True:
    try:
    if magtag.peripherals.button_a_pressed:
    use_sound = not use_sound # toggle sound
    print(TAG+f"button A pressed. Switching sound {"on" if use_sound else "off"}")
    s1 = "button A pressed."
    s2 = f"Switching sound {"on" if use_sound else "off"}"
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_b_pressed:
    use_leds = not use_leds # toggle leds
    print(TAG+f"button B pressed. Switching LEDs {"on" if use_leds else "off"}")
    s1 = "button B pressed."
    s2 = f"Switching LEDs {"on" if use_leds else "off"}"
    print(TAG+f"{s1} {s2}")
    pr_msg([s1, s2])
    pr_th_msg() # rewrite the temperature & humidity page
    if magtag.peripherals.button_c_pressed:
    pass
    wait_for_zero_sec = not wait_for_zero_sec
    print(TAG+f"button C pressed. Start time wait for zero seconds {"on" if wait_for_zero_sec else "off"}")
    wr_to_toml(toml_zero_sec)
    if magtag.peripherals.button_d_pressed:
    pass
    my_debug = not my_debug
    print(TAG+f"button d pressed. Switching debug print statements {"on" if my_debug else "off"}")
    wr_to_toml(toml_debug)

    if not rtc_set:
    get_time_fm_aio()
    curr_tm = time.time() # set curr_tm for the first time
    @@ -492,8 +696,8 @@ def main():
    # print(TAG+f"ct= {ct}, curr_tm= {curr_tm}. Difference= {ct - curr_tm} secs.")
    # print(TAG+f"c_diff % {dt1}= {c1}. c_diff % {dt2}= {c2}. Looping...")
    print(TAG+"c_diff % {:3d}= {:4d}. c_diff % {:4d}= {:4d}. Looping...".format(dt1, c1, dt2, c2))
    # if start or (not sensor) or (c2 >= (dt2 - 10) and c2 <= dt2) and (not msg_sent): # 5 min interval (give some space)
    if start or (not sensor) or (c1 >= (dt1 - 10) and c1 <= dt1) and (not msg_sent): # 5 min interval (give some space)
    # if start or (not sensor) or (c1 >= (dt1 - 10) and c1 <= dt1) and (not msg_sent): # 5 min interval (give some space)
    if start or (not sensor) or (c2 >= (dt2 - 10) and c2 <= dt2) and (not msg_sent): # 5 min interval (give some space)
    start = False
    blink_leds() # switch off LEDs
    get_th_direct() # sensor directly connected to MAGTAG board via I2C/Stemma_QT
  30. PaulskPt revised this gist Mar 25, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion code.py
    Original file line number Diff line number Diff line change
    @@ -468,7 +468,7 @@ def main():
    use_sound = not use_sound # toggle sound
    print(TAG+f"button A pressed. Switching sound {"on" if use_sound else "off"}")
    if magtag.peripherals.button_b_pressed:
    use_leds = not use_leds
    use_leds = not use_leds # toggle leds
    print(TAG+f"button B pressed. Switching LEDs {"on" if use_leds else "off"}")
    if magtag.peripherals.button_c_pressed:
    pass