Rewrite sun component calculations (#1661)

This commit is contained in:
Otto Winter
2021-04-07 12:16:36 +02:00
committed by GitHub
parent e0c5b45694
commit 7964b724ed
4 changed files with 391 additions and 216 deletions
+50 -63
View File
@@ -8,85 +8,72 @@
namespace esphome {
namespace sun {
namespace internal {
/* Usually, ESPHome uses single-precision floating point values
* because those tend to be accurate enough and are more efficient.
*
* However, some of the data in this class has to be quite accurate, so double is
* used everywhere.
*/
using num_t = double;
struct GeoLocation {
num_t latitude;
num_t longitude;
num_t latitude_rad() const;
num_t longitude_rad() const;
};
struct Moment {
time::ESPTime dt;
num_t jd() const;
num_t jde() const;
};
struct EquatorialCoordinate {
num_t right_ascension;
num_t declination;
num_t right_ascension_rad() const;
num_t declination_rad() const;
};
struct HorizontalCoordinate {
num_t elevation;
num_t azimuth;
num_t elevation_rad() const;
num_t azimuth_rad() const;
};
} // namespace internal
class Sun {
public:
void set_time(time::RealTimeClock *time) { time_ = time; }
time::RealTimeClock *get_time() const { return time_; }
void set_latitude(double latitude) { latitude_ = latitude; }
void set_longitude(double longitude) { longitude_ = longitude; }
void set_latitude(double latitude) { location_.latitude = latitude; }
void set_longitude(double longitude) { location_.longitude = longitude; }
optional<time::ESPTime> sunrise(double elevation = 0.0);
optional<time::ESPTime> sunset(double elevation = 0.0);
optional<time::ESPTime> sunrise(double elevation);
optional<time::ESPTime> sunset(double elevation);
double elevation();
double azimuth();
protected:
double current_sun_time_() { return this->calc_sun_time_(this->time_->utcnow()); }
/** Calculate the declination of the sun in rad.
*
* See https://en.wikipedia.org/wiki/Position_of_the_Sun#Declination_of_the_Sun_as_seen_from_Earth
*
* Accuracy: ±0.2°
*
* @param sun_time The day of the year, 1 means January 1st. See calc_sun_time_.
* @return Sun declination in degrees
*/
double sun_declination_(double sun_time);
double elevation_ratio_(double sun_time);
/** Calculate the hour angle based on the sun time of day in hours.
*
* Positive in morning, 0 at noon, negative in afternoon.
*
* @param sun_time Sun time, see calc_sun_time_.
* @return Hour angle in rad.
*/
double hour_angle_(double sun_time);
double elevation_(double sun_time);
double elevation_rad_(double sun_time);
double zenith_rad_(double sun_time);
double azimuth_rad_(double sun_time);
double azimuth_(double sun_time);
/** Return the sun time given by the time_ object.
*
* Sun time is defined as doubleing point day of year.
* Integer part encodes the day of the year (1=January 1st)
* Decimal part encodes time of day (1/24 = 1 hour)
*/
double calc_sun_time_(const time::ESPTime &time);
uint32_t calc_epoch_(time::ESPTime base, double sun_time);
/** Calculate the sun time of day
*
* @param day_of_year
* @param elevation
* @param rising
* @return
*/
double sun_time_for_elevation_(int32_t day_of_year, double elevation, bool rising);
double latitude_rad_();
internal::HorizontalCoordinate calc_coords_();
optional<time::ESPTime> calc_event_(bool rising, double zenith);
time::RealTimeClock *time_;
/// Latitude in degrees, range: -90 to 90.
double latitude_;
/// Longitude in degrees, range: -180 to 180.
double longitude_;
internal::GeoLocation location_;
};
class SunTrigger : public Trigger<>, public PollingComponent, public Parented<Sun> {
public:
SunTrigger() : PollingComponent(1000) {}
SunTrigger() : PollingComponent(60000) {}
void set_sunrise(bool sunrise) { sunrise_ = sunrise; }
void set_elevation(double elevation) { elevation_ = elevation; }