async def daylight(self) -> None: """Task to determine when it is daylight and daylight changes.""" while True: astral_now = now(tzinfo=self._tzinfo) previous = self._daylight if astral_now < self._dawn: self._daylight = False next_event = self._dawn - astral_now info = "Night: inverter data collection is inactive, cached updates being used" elif astral_now > self._dusk: self._daylight = False tomorrow = astral_now + datetime.timedelta(days=1) astral = sun(date=tomorrow.date(), observer=self._siteinfo.observer, tzinfo=self._tzinfo) next_event = astral['dawn'] - astral_now info = "Night: inverter data collection is inactive, cached updates being used" else: self._daylight = True next_event = self._dusk - astral_now info = f"Daylight: inverter data collection is active and sampling every at {self._sampling_fast} (fast), {self._sampling_medium} (medium), {self._sampling_slow} (slow) seconds" if previous != self._daylight: _LOGGER.info(f"{info}") FUDGE = 60 await asyncio.sleep(next_event.total_seconds() + FUDGE)
async def solar_data_update(self) -> None: """Update the sun data used to sequence operation.""" astral_now = now(tzinfo=self._tzinfo) astral = sun(observer=self._siteinfo.observer, tzinfo=self._tzinfo) self._dawn = astral['dawn'] self._dusk = astral['dusk'] self._daylight = self._dawn < astral_now < self._dusk _LOGGER.info(f"Dawn occurs at {self._dawn.strftime('%H:%M')}, " f"noon is at {astral['noon'].strftime('%H:%M')}, " f"and dusk occurs at {self._dusk.strftime('%H:%M')} " f"on this {day_of_year()} day of {astral_now.year}")
async def sun_position(self): """Calculate where the sun is in the sky.""" astral_now = now(tzinfo=self._tzinfo) sun_elevation = elevation(observer=self._siteinfo.observer, dateandtime=astral_now) sun_azimuth = azimuth(observer=self._siteinfo.observer, dateandtime=astral_now) results = [{ 'topic': 'sun/position', 'elevation': round(sun_elevation, 1), 'azimuth': round(sun_azimuth, 1) }] return results
def elevation( observer: Observer, dateandtime: Optional[datetime.datetime] = None, with_refraction: bool = True, ) -> float: """Calculate the sun's angle of elevation. Args: observer: Observer to calculate the solar elevation for dateandtime: The date and time for which to calculate the angle. If `dateandtime` is None or is a naive Python datetime then it is assumed to be in the UTC timezone. with_refraction: If True adjust elevation to take refraction into account Returns: The elevation angle in degrees above the horizon. """ if dateandtime is None: dateandtime = now(pytz.UTC) return 90.0 - zenith(observer, dateandtime, with_refraction)
def zenith( observer: Observer, dateandtime: Optional[datetime.datetime] = None, with_refraction: bool = True, ) -> float: """Calculate the zenith angle of the sun. Args: observer: Observer to calculate the solar zenith for dateandtime: The date and time for which to calculate the angle. If `dateandtime` is None or is a naive Python datetime then it is assumed to be in the UTC timezone. with_refraction: If True adjust zenith to take refraction into account Returns: The zenith angle in degrees. """ if dateandtime is None: dateandtime = now(pytz.UTC) return zenith_and_azimuth(observer, dateandtime, with_refraction)[0]
def azimuth( observer: Observer, dateandtime: Optional[datetime.datetime] = None, ) -> float: """Calculate the azimuth angle of the sun. Args: observer: Observer to calculate the solar azimuth for dateandtime: The date and time for which to calculate the angle. If `dateandtime` is None or is a naive Python datetime then it is assumed to be in the UTC timezone. Returns: The azimuth angle in degrees clockwise from North. If `dateandtime` is a naive Python datetime then it is assumed to be in the UTC timezone. """ if dateandtime is None: dateandtime = now(pytz.UTC) return zenith_and_azimuth(observer, dateandtime)[1]
def test_australia(self): td = now(timezone("Australia/Melbourne")) assert td.hour == 1 assert td.minute == 20
def test_default_timezone(self): td = now() assert td.hour == 14 assert td.minute == 10 assert td.second == 20