adafruit / Adafruit_Learning_System_Guides

Programs and scripts to display "inline" in Adafruit Learning System guides
MIT License
997 stars 769 forks source link

Star_Fragment_Lamp code has an issue with sunrise #2609

Open clarkiej opened 1 year ago

clarkiej commented 1 year ago

Board flashed with adafruit-circuitpython-adafruit_qtpy_esp32s2-en_GB-8.2.4.uf2 Used CircuitPython 8.x code / library version

The lamp has no issues with determining sunset and approx.one hour outy and slowly increasing brightness till sunset is reached:

17:13:32.913 -> pinging Open-Meteo 17:13:40.931 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=17, tm_min=13, tm_sec=40, tm_wday=2, tm_yday=241, tm_isdst=0) 17:13:40.976 -> 0 hour(s) until sunset 17:13:40.976 -> 48 minutes(s) until sunset 17:13:40.976 -> 2023-08-29T18:02 17:13:40.976 -> 0 17:13:40.976 -> 17:13:40.976 -> pinging Open-Meteo 17:13:48.915 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=17, tm_min=13, tm_sec=47, tm_wday=2, tm_yday=241, tm_isdst=0) 17:13:48.959 -> 0 hour(s) until sunset 17:13:48.959 -> 48 minutes(s) until sunset <<--approx one hour hout it goes into teh countown loop increasing LED brightness 17:13:48.959 -> 2023-08-29T18:02 17:13:48.959 -> 47.5424 17:13:48.959 ->

Once sunset time is reached "the star is glowing" waits till after midnight to look for sunrise:

18:00:03.974 -> pinging Open-Meteo 18:00:11.164 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=18, tm_min=0, tm_sec=10, tm_wday=2, tm_yday=241, tm_isdst=0) 18:00:11.164 -> 0 hour(s) until sunset 18:00:11.164 -> 1 minutes(s) until sunset 18:00:11.164 -> 2023-08-29T18:02 18:00:11.164 -> 229.068 18:00:11.164 -> 18:05:04.015 -> pinging Open-Meteo 18:05:11.282 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=18, tm_min=5, tm_sec=10, tm_wday=2, tm_yday=241, tm_isdst=0) 18:05:11.315 -> 23 hour(s) until sunset 18:05:11.315 -> 56 minutes(s) until sunset 18:05:11.315 -> 2023-08-29T18:02 18:05:11.315 -> 250.678 18:05:11.315 -> 18:05:11.315 -> star is glowing 18:30:06.932 -> not looking for sunrise 18:30:06.979 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=18, tm_min=30, tm_sec=6, tm_wday=2, tm_yday=241, tm_isdst=0) 18:30:06.979 ->

The trouble is that approx. 1 hour out from sunrise, instead of counting down to sunrise and decreasing brightness, the star is instead turned off and the lamp goes back to looking for sunset:

05:26:57.051 -> 05:41:49.895 -> pinging Open-Meteo 05:41:57.433 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=5, tm_min=41, tm_sec=57, tm_wday=2, tm_yday=241, tm_isdst=0) 05:41:57.479 -> 0 hour(s) until sunrise 05:41:57.479 -> 59 minutes(s) until sunrise 05:41:57.479 -> 2023-08-29T06:40 05:41:57.479 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=5, tm_min=41, tm_sec=57, tm_wday=2, tm_yday=241, tm_isdst=0) 05:41:57.479 -> 05:41:57.479 -> 0 hour(s) until sunrise 05:41:57.479 -> 59 minutes(s) until sunrise 05:41:57.479 -> 2023-08-29T06:40 05:41:57.479 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=5, tm_min=41, tm_sec=57, tm_wday=2, tm_yday=241, tm_isdst=0) 05:41:57.479 -> 05:41:57.479 -> star is off <<-- one hour out instead of counting down the lamp is turned off 05:56:49.925 -> pinging Open-Meteo 05:56:57.751 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=29, tm_hour=5, tm_min=56, tm_sec=56, tm_wday=2, tm_yday=241, tm_isdst=0) 05:56:57.751 -> 12 hour(s) until sunset 05:56:57.751 -> 4 minutes(s) until sunset 05:56:57.751 -> 2023-08-29T18:02 05:56:57.751 -> 0

BlitzCityDIY commented 1 year ago

hihi- thanks for the serial output. in looking at the code, i'm wondering if it's the rise_time and set_time variables not being reset. can you try adding rise_time = divide_time(sunrise) to looking_for_sunrise (line 229):

if looking_for_sunrise:
                    print("pinging Open-Meteo")
                    sunrise, sunset = sun_clock()
                    rise_time = divide_time(sunrise)
                    (total_until_rise, hours_until_sunrise,
                    mins_until_sunrise, now) = sun_countdown(rise_time)

and set_time = divide_time(sunset) to the sunset portion (line 188):

if first_run or ticks_diff(ticks_ms(), clock) > time_check:
                print("pinging Open-Meteo")
                sunrise, sunset = sun_clock()
                set_time = divide_time(sunset)
                (total_until_set, hours_until_sunset,
                mins_until_sunset, now) = sun_countdown(set_time)
clarkiej commented 1 year ago

Thank you for your prompt reply. Much appreciated. I had someone help me in working out how access the serial output, and adding the time stamp to see what is actually happening when relative to my time. I have made the change and let you know the result.

clarkiej commented 1 year ago

I also have a second problem with my location and timezone.

If I enter my Lat/Long as Perth

lat = -31.95224 long = 115.8614

and even type my location as Australia/Perth

location = "Australia/Perth"

and power up teh lamp, the correct sunrise and sunset times are pulled from the API, but the star glow is set to false and the lamp is off, even though sunrise has not yet occured :

Location set to Perth with timestamp showing Perth Time (2023-08-31)

04:31:33.325 -> ]0;🐍192.168.1.241 | code.py | 8.2.4\struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=31, tm_sec=36, tm_wday=4, tm_yday=243, tm_isdst=0) 04:31:40.832 -> 2023-08-31T06:37 <<-- Perth Sunrise 04:31:40.878 -> 2023-08-31T18:03 <<-- Perth Sunset 04:31:44.682 -> 48676 04:31:44.682 -> star glow false <<-- sunrise still ahead but lamp off 04:31:44.682 -> pinging Open-Meteo 04:31:51.633 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=31, tm_sec=51, tm_wday=4, tm_yday=243, tm_isdst=0) 04:31:51.633 -> 13 hour(s) until sunset 04:31:51.633 -> 31 minutes(s) until sunset 04:31:51.633 -> 2023-08-31T18:03 04:31:51.633 -> 0

Same applies if I set my LAT/LONG and Location to "Asia/Singapore"

This means if there is a connection loss and a soft reset after midnight, then the lamp will turn off and track time to sunset.

But if I set my LAT/LONG to London and location to "UK/London" then it sees that the sun has not risen, lamp is turned on and time to sunrise is tracked

Time Stamp still Perth time (2023-08-31) 04:50:11.769 -> code.py output: 04:50:11.769 -> ]0;🐍192.168.1.241 | code.py | 8.2.4\struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=50, tm_sec=15, tm_wday=4, tm_yday=243, tm_isdst=0) 04:50:19.379 -> 2023-08-30T06:10 <<-- London Sunrise 04:50:19.380 -> 2023-08-30T19:51 <<-- London Sunset 04:50:23.212 -> -32363 04:50:23.212 -> star glow true <<-- Sunrise still ahead turn on lamp 04:50:23.212 -> pinging Open-Meteo 04:50:30.175 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=50, tm_sec=29, tm_wday=4, tm_yday=243, tm_isdst=0) 04:50:30.208 -> 1 hour(s) until sunrise 04:50:30.208 -> 19 minutes(s) until sunrise 04:50:30.208 -> 2023-08-30T06:10 04:50:30.208 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=50, tm_sec=29, tm_wday=4, tm_yday=243, tm_isdst=0) 04:50:30.208 ->

BlitzCityDIY commented 1 year ago

ah okay i think this has to do with the first_run parameter. it assumes it's during daylight hours (looking for sunset). i'm going to add some logic so that it determines before the loop dynamically if it's night or day.

clarkiej commented 1 year ago

Update:
This is the result of teh code change. I was able to have the lamp glow when powering up after midnight and before sunrise for testing by using London as my LAT/Long and it has just hit one hour before sunrise, but it is still ignoring the loop countdown and turning the lamp off:

04:55:36.985 -> ]0;🐍Wi-Fi: No IP | Done | 8.2.4\ 04:55:39.149 -> Auto-reload is on. Simply save files over USB to run them or enter REPL to disable. 04:55:39.149 -> code.py output: 04:55:39.149 -> ]0;🐍192.168.1.241 | code.py | 8.2.4\struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=55, tm_sec=42, tm_wday=4, tm_yday=243, tm_isdst=0) 04:55:46.645 -> 2023-08-30T06:10 <<--London Sunrise as it is showing yesterday's (for me) date 04:55:46.645 -> 2023-08-30T19:51 04:55:50.486 -> -32690 04:55:50.486 -> star glow true 04:55:50.486 -> pinging Open-Meteo 04:55:57.419 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=55, tm_sec=57, tm_wday=4, tm_yday=243, tm_isdst=0) 04:55:57.465 -> 1 hour(s) until sunrise 04:55:57.465 -> 14 minutes(s) until sunrise 04:55:57.465 -> 2023-08-30T06:10 04:55:57.465 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=4, tm_min=55, tm_sec=57, tm_wday=4, tm_yday=243, tm_isdst=0) 04:55:57.465 -> 05:10:50.478 -> pinging Open-Meteo 05:10:57.618 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=5, tm_min=10, tm_sec=57, tm_wday=4, tm_yday=243, tm_isdst=0) 05:10:57.664 -> 0 hour(s) until sunrise 05:10:57.664 -> 59 minutes(s) until sunrise <<-- less than an hour to go to sunup 05:10:57.664 -> 2023-08-30T06:10 05:10:57.664 -> struct_time(tm_year=2023, tm_mon=8, tm_mday=31, tm_hour=5, tm_min=10, tm_sec=57, tm_wday=4, tm_yday=243, tm_isdst=0) 05:10:57.664 -> 05:10:57.664 -> star is off <<-- oops

clarkiej commented 1 year ago

Have you been able to investigate this any further?

that-fleps commented 1 year ago

I've been working through debugging my Star-Fragment lamp too and it seems like I've come across something that could at least be related or maybe a confounding issue, so I'll add some notes here in case it helps.

Brief summary of findings so far: there was some discussion on the Adafruit Forum of a Star-Fragment lamp not working at https://forums.adafruit.com/viewtopic.php?t=204011 and my lamp - which also used to work ok - seemed to have stopped tracking sunset times (it was used mostly as a nightlight before bedtime). If switched on in the evening:

This change seemed to have happened sometime around the end of August 2023. I'm not sure exactly when as we were away travelling and the lamp wasn't being used.

In attempting to work out why it wasn't behaving, I checked the log output in the REPL pane of the Mu editor, which (at just after 7pm on 10th September in New Zealand) looked something like:

code.py output:
struct_time(tm_year=2023, tm_mon=9, tm_mday=10, tm_hour=7, tm_min=8, tm_sec=30, tm_wday=0, tm_yday=253, tm_isdst=0)

2023-09-10T06:34
2023-09-10T18:07
39503
star glow false
pinging Open-Meteo
struct_time(tm_year=2023, tm_mon=9, tm_mday=10, tm_hour=7, tm_min=8, tm_sec=44, tm_wday=0, tm_yday=253, tm_isdst=0)

10 hour(s) until sunset
58 minutes(s) until sunset
2023-09-10T18:07
0

which looked mostly ok, except the time in the struct_time returned by the IO_HTTP call to AdafruitIO appears to be 12 hours before my local time (Pacific/Auckland). From there the time-to-sunset calculation looks like it's performed correctly, just based on the wrong current time.

My understanding is that the IO_HTTP call doesn't take a timezone/location parameter and instead determines the client's timezone by IP address. So in Auckland I would have expected the struct_time to look like

struct_time(tm_year=2023, tm_mon=9, tm_mday=10, tm_hour=**19**, tm_min=8, tm_sec=44, tm_wday=0, tm_yday=253, tm_isdst=0)

As a follow-up I tried using an alternative method for getting local time, based on an example from the Adafruit Funhouse project at https://learn.adafruit.com/adafruit-funhouse/getting-the-date-time which seemed to be common to several other projects too. Running at approx 2.30pm in Auckland the REPL output looked like

Fetching text from https://io.adafruit.com/api/v2/my-username/integrations/time/strftime?x-aio-key=my-key&tz=Pacific/Auckland&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z
----------------------------------------
2023-09-14 14:30:12.491 257 4 +1200 NZST
----------------------------------------

which did match my localtime.

User mikeysklar on the Adafruit Forum noted that there's an open bug against the Adafruit_CircuitPython_AdafruitIO library in which io.receive_time() returns a time in UTC

https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/issues/95

It looks like this behaviour was only intermittent when the bug was originally reported, but the IO_HTTP call in the Star Fragment code has been returning me a time 12 hours earlier than expected (i.e. a time that looks a lot like UTC) every time I've tried it lately, so possibly the bug has resurfaced and it's now consistently returning UTC.

The github issue notes that there's a workaround for the issue using a TZIO class (provided), so in the meantime I've had a go at adjusting the Star-Fragment code to use the workaround, i.e.

# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT

import os
import ssl
import time
import microcontroller
import board
import wifi
import socketpool
import adafruit_requests
import neopixel
import simpleio
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
from adafruit_io.adafruit_io import IO_HTTP

# latitude
lat = # *** update me ***
# longitude
long = # *** update me ***

# neopixel setup
NUMPIXELS = 16  # number of neopixels
BRIGHTNESS = 0.4  # A number between 0.0 and 1.0, where 0.0 is off, and 1.0 is max.
PIN = board.A3  # This is the default pin on the NeoPixel Driver BFF.

pixels = neopixel.NeoPixel(PIN, NUMPIXELS, brightness=BRIGHTNESS, auto_write=False)

# turn on NeoPixels on boot to check wiring
pixels.fill((255, 125, 0))
pixels.show()

# API request to open-meteo
weather_url = "https://api.open-meteo.com/v1/forecast?"
# pass latitude and longitude
# will return sunrise and sunset times
weather_url += "latitude=%d&longitude=%d&timezone=auto&daily=sunrise,sunset" % (lat, long)

#  connect to SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

pool = socketpool.SocketPool(wifi.radio)

# adafruit IO info
aio_username = os.getenv('aio_username')
aio_key = os.getenv('aio_key')
location = "Pacific/Auckland" # update this value, also could go into settings.toml

# function for adjusting for timezone
class TZIO(IO_HTTP):
    def receive_time(self, tz=location):
        path = self._compose_path("integrations/time/struct.json?tz={}".format(tz))
        time_struct = self._get(path)
        return time.struct_time(
            (
                time_struct["year"],
                time_struct["mon"],
                time_struct["mday"],
                time_struct["hour"],
                time_struct["min"],
                time_struct["sec"],
                time_struct["wday"],
                time_struct["yday"],
                time_struct["isdst"],
            )
        )

# io HTTP for getting the time from the internet
# io = IO_HTTP(aio_username, aio_key, requests) 
io = TZIO(aio_username, aio_key, requests) # updated with this line to use TZIO instead

def reset_on_error(delay, error):
    print("Error:\n", str(error))
    print("Resetting microcontroller in %d seconds" % delay)
    time.sleep(delay)
    microcontroller.reset()

# code continues as originally ...

and this looks like it's now working ok. The struct_time shown in the REPL output matches my local time now, and the lamp is back to brightening for sunset/switching on fully if it's already dark as expected.

Hope this helps in the meantime.

that-fleps commented 1 year ago

hmm, TL-DR version ...

So, if the io.receive_time() bug has resurfaced and it's sending UTC instead of localtime, options might be:

I've added the TZIO workaround to the code on my lamp and it seems to be back working ok now. Debug messages in MuEdit/REPL show localtimes being returned and used for calculating time-to-sunset etc.

clarkiej commented 1 year ago

Thank you @that-fleps . I will add in your TZIO workaround and update on what happens in the morning. It is now after sunset, so I will let it run glowing and monitor the serial port, and update in the morning. I have no problems with the Sunset function, but for me sunrise is the issue. One hour before sunrise the lamp just turns off, no countdown. If there is a soft reboot after midnight and before sunrise, the lamp just reverts back to looking for sunset and ignores the upcoming sunrise.

clarkiej commented 1 year ago

I have let the lamp run till 1 hour before sunrise, and time is being calculated correctly, but unfortunately teh TZIO workaround does not correct the issue where instead of switching to counting down and darkening teh LED's one hour before sunrise, it still flips straight to turning the lamp off and tracking time till sunset :

4:56:32.323 -> pinging Open-Meteo 04:56:39.554 -> struct_time(tm_year=2023, tm_mon=9, tm_mday=22, tm_hour=4, tm_min=56, tm_sec=39, tm_wday=5, tm_yday=265, tm_isdst=0) 04:56:39.599 -> 1 hour(s) until sunrise 04:56:39.599 -> 14 minutes(s) until sunrise <-- all good tracking sunrise 04:56:39.599 -> 2023-09-22T06:10 04:56:39.599 -> struct_time(tm_year=2023, tm_mon=9, tm_mday=22, tm_hour=4, tm_min=56, tm_sec=39, tm_wday=5, tm_yday=265, tm_isdst=0) 04:56:39.599 -> 05:11:32.307 -> pinging Open-Meteo 05:11:39.413 -> struct_time(tm_year=2023, tm_mon=9, tm_mday=22, tm_hour=5, tm_min=11, tm_sec=38, tm_wday=5, tm_yday=265, tm_isdst=0) 05:11:39.474 -> 0 hour(s) until sunrise 05:11:39.474 -> 59 minutes(s) until sunrise 05:11:39.474 -> 2023-09-22T06:10 05:11:39.474 -> struct_time(tm_year=2023, tm_mon=9, tm_mday=22, tm_hour=5, tm_min=11, tm_sec=38, tm_wday=5, tm_yday=265, tm_isdst=0) 05:11:39.474 -> 05:11:39.474 -> star is off <-- an hour to go, oops no countdown, just turen lamp off 05:26:32.437 -> pinging Open-Meteo 05:26:39.650 -> struct_time(tm_year=2023, tm_mon=9, tm_mday=22, tm_hour=5, tm_min=26, tm_sec=39, tm_wday=5, tm_yday=265, tm_isdst=0) 05:26:39.716 -> 12 hour(s) until sunset 05:26:39.716 -> 48 minutes(s) until sunset <--- straight to tracking time till sunset 05:26:39.716 -> 2023-09-22T18:15 05:26:39.716 -> 0

Rebooting within the one hour before sunrise the lamp also disregards sunrise time, turns the lamp off and just goes to searching for sunset.

clarkiej commented 10 months ago

Do we have an update on the inability to dim the lamp while counting down to sunrise?