Розрахунок сходу і заходу сонця. Автоматизація освітлення

У системах домашньої автоматизації може знадобитися інформація про сході і заході нашого світила. За відсутності додаткових датчиків можна автоматично включати і вимикати вуличне, садове освітлення, нічники, системи автополиву та інше.

Я вже писав про те, як я вирішив задачу управління вуличним освітленням за допомогою камери відеоспостереження . Мінус даного рішення полягає в тому, що чутливість сучасних камер досить висока, а значить вловити поріг зниження яскравості зображення можна тільки тоді, коли на вулиці вже зовсім стемніє. Особливо актуальна проблема взимку, коли додатковий вплив на загальну яскравість зображення надає сніг.

Тому я вирішив розраховувати щодня схід і захід сонця, щоб управляти вуличним освітленням більш точно. Але, як це часто буває, завдання виявилося досить складною. Утворилася маса складних формул, понять, таблиць. Одним словом, самостійно цей горіх розгризти я не зміг, а точніше не захотів, тому що знайшов вже готовий клас для PHP.

&lt;? Php class sun {var $ latitude; #szerokosc geograficzna var $ longitude; #dlugosc geograficzna var $ timezone; #strefa czasowa function sun ($ latitude, $ longitude, $ timezone) {$ this-> latitude = $ latitude; $ This-> longitude = $ longitude; $ This-> timezone = $ timezone; $ This-> yday = date ( "z"); $ This-> mon = date ( "n"); $ This-> mday = date ( "j"); $ This-> year = date ( "Y"); # --------------------- $ this-> DST = $ this-> is_daylight_time (date ( "U")); if ($ this-> DST) {$ this-> timezone = ($ this-> timezone + 1); } If ($ this-> timezone == "13") {$ this-> timezone = "-11"; } # --------------------- $ this-> A = 1.5708; $ This-> B = 3.14159; $ This-> C = 4.71239; $ This-> D = 6.28319; $ This-> E = 0.0174533 * $ this-> latitude; $ This-> F = 0.0174533 * $ this-> longitude; $ This-> G = 0.261799 * $ this-> timezone; # --------------------- # For astronomical twilight, use # $ this-> R = -.309017; # For nautical twilight, use # $ this-> R = -.207912; # For civil twilight, use # $ this-> R = -.104528; # For sunrise or sunset, use $ this-> R = -.0145439; # ---------------------} function is_daylight_time ($ time) {list ($ dom, $ dow, $ month, $ hour, $ min) = explode ( ":", date ( "d: w: m: H: i", $ time)); if ($ month> 4 && $ month <10) {$ this-> retval = 1; # May thru September} elseif ($ month == 4 && $ dom> 7) {$ this-> retval = 1; # After first week in April} elseif ($ month == 4 && $ dom <= 7 && $ dow == 0 && $ hour> = 2) {$ this-> retval = 1; # After 2am on first Sunday ($ dow = 0) in April} elseif ($ month == 4 && $ dom <= 7 && $ dow! = 0 && ($ dom- $ dow> 0)) {$ this-> retval = 1; # After Sunday of first week in April} elseif ($ month == 10 && $ dom <25) {$ this-> retval = 1; # Before last week of October} elseif ($ month == 10 && $ dom> = 25 && $ dow == 0 && $ hour <2) {$ this-> retval = 1; # Before 2am on last Sunday in October} elseif ($ month == 10 && $ dom> = 25 && $ dow! = 0 && ($ dom-24- $ dow <1)) {$ this-> retval = 1; # Before Sunday of last week in October} else {$ this-> retval = 0; } Return $ this-> retval; } Function sunrise () {$ J = $ this-> A; $ K = $ this-> yday + (($ J - $ this-> F) / $ this-> D); $ L = ($ K * .017202) - .0574039; # Solar Mean Anomoly $ M = $ L + .0334405 * sin ($ L); # Solar True Longitude $ M + = 4.93289 + (3.49066E-04) * sin (2 * $ L); if ($ this-> D == 0) {echo "Trying to normalize with zero offset ..."; exit; } While ($ M <0) {$ M = ($ M + $ this-> D); } While ($ M> = $ this-> D) {$ M = ($ M - $ this-> D); } If (($ M / $ this-> A) - intval ($ M / $ this-> A) == 0) {$ M + = 4.84814E-06; } $ P = sin ($ M) / cos ($ M); # Solar Right Ascension $ P = atan2 (.91746 * $ P, 1); # Quadrant Adjustment if ($ M> $ this-> C) {$ P + = $ this-> D; } Else {if ($ M> $ this-> A) {$ P + = $ this-> B; }} $ Q = .39782 * sin ($ M); # Solar Declination $ Q = $ Q / sqrt (- $ Q * $ Q + 1); # This is how the original author wrote it! $ Q = atan2 ($ Q, 1); $ S = $ this-> R - (sin ($ Q) * sin ($ this-> E)); $ S = $ S / (cos ($ Q) * cos ($ this-> E)); if (abs ($ S)> 1) {echo 'none'; } # Null phenomenon $ S = $ S / sqrt (- $ S * $ S + 1); $ S = $ this-> A - atan2 ($ S, 1); $ S = $ this-> D - $ S; $ T = $ S + $ P - 0.0172028 * $ K - 1.73364; # Local apparent time $ U = $ T - $ this-> F; # Universal timer $ V = $ U + $ this-> G; # Wall clock time # Quadrant Determination if ($ this-> D == 0) {echo "Trying to normalize with zero offset ..."; exit; } While ($ V <0) {$ V = ($ V + $ this-> D); } While ($ V> = $ this-> D) {$ V = ($ V - $ this-> D); } $ V = $ V * 3.81972; $ Hour = intval ($ V); $ Min = intval ((($ V - $ hour) * 60) + 0.5); // return date ( "G: i", mktime ($ hour, $ min, 0, $ this-> mon, $ this-> mday, $ this-> year) - 1800); return mktime ($ hour, $ min, 0, $ this-> mon, $ this-> mday, $ this-> year) - 1800; } Function sunset () {$ J = $ this-> C; $ K = $ this-> yday + (($ J - $ this-> F) / $ this-> D); $ L = ($ K * .017202) - .0574039; # Solar Mean Anomoly $ M = $ L + .0334405 * sin ($ L); # Solar True Longitude $ M + = 4.93289 + (3.49066E-04) * sin (2 * $ L); if ($ this-> D == 0) {echo "Trying to normalize with zero offset ..."; exit; } While ($ M <0) {$ M = ($ M + $ this-> D); } While ($ M> = $ this-> D) {$ M = ($ M - $ this-> D); } If (($ M / $ this-> A) - intval ($ M / $ this-> A) == 0) {$ M + = 4.84814E-06; } $ P = sin ($ M) / cos ($ M); # Solar Right Ascension $ P = atan2 (.91746 * $ P, 1); # Quadrant Adjustment if ($ M> $ this-> C) {$ P + = $ this-> D; } Else {if ($ M> $ this-> A) {$ P + = $ this-> B; }} $ Q = .39782 * sin ($ M); # Solar Declination $ Q = $ Q / sqrt (- $ Q * $ Q + 1); # This is how the original author wrote it! $ Q = atan2 ($ Q, 1); $ S = $ this-> R - (sin ($ Q) * sin ($ this-> E)); $ S = $ S / (cos ($ Q) * cos ($ this-> E)); if (abs ($ S)> 1) {echo 'none'; } # Null phenomenon $ S = $ S / sqrt (- $ S * $ S + 1); $ S = $ this-> A - atan2 ($ S, 1); # $ S = $ this-> D - $ S; $ T = $ S + $ P - 0.0172028 * $ K - 1.73364; # Local apparent time $ U = $ T - $ this-> F; # Universal timer $ V = $ U + $ this-> G; # Wall clock time # Quadrant Determination if ($ this-> D == 0) {echo "Trying to normalize with zero offset ..."; exit; } While ($ V <0) {$ V = ($ V + $ this-> D); } While ($ V> = $ this-> D) {$ V = ($ V - $ this-> D); } $ V = $ V * 3.81972; $ Hour = intval ($ V); $ Min = intval ((($ V - $ hour) * 60) + 0.5); // return date ( "G: i", mktime ($ hour, $ min, 0, $ this-> mon, $ this-> mday, $ this-> year) + 1800); return mktime ($ hour, $ min, 0, $ this-> mon, $ this-> mday, $ this-> year) +1800; }} // $ ext_light = show_list ($ keys_id, "# key_pio #", "", 1, "key_label = 'ext_light'", 1); $ Sun = new sun ('55 .72 ', '37 .63', '3'); $ My_sunrise = $ sun-> sunrise (); $ My_sunset = $ sun-> sunset (); if (time ()> = $ my_sunrise && $ ext_light == 1 && time () <$ my_sunset) echo "Вимкнути світло"; if (time ()> = $ my_sunset && $ ext_light == 0) echo "Включити світло"; ?>

Клас я знайшов на якомусь польському сайті.
Користуватися класом досить просто. Необхідно тільки знати широту, довготу і часовий пояс. Широту і довготу конкретної місцевості можна підглянути за допомогою Google API. Якщо комусь треба - розповім як.

Наприклад, для Москви це:

$ Sun = new sun ('55 .72 ', '37 .63', '3');

Я тільки змінив функції sunset () і sunrise () таким чином, щоб світло вимикався на 1800 секунд (30 хвилин) раніше і включався на 30 хвилин пізніше астрономічного сходу і заходу сонця. Це вияснілоась експериментальним шляхом. Тому у відповідних функціях змініть або зовсім приберіть корекцію.
Якщо вам необхідно, щоб функції повертали значення в людському вигляді, закоментуйте останній return і приберіть коментар з передостаннього.

Автор: Andrey_B
Будь-яке використання матеріалів сайту можливе лише з дозволу автора і з обов'язковим посиланням на джерело.



Сортування коментарів: Останні зверху | перші зверху

2018-06-30 2:49:55 | nihil
Добрий день. Теж почав копати в цьому напрямку. Але прочитавши Вашу статтю про датчик освітленості і зрозумів що з нього зчитувати простіше. Далі пара експерементів і готово;)


2016-03-27 14:53:53 | Олександр Т.
Підкажіть, як цей функціонал додати в демо інтерфейс?


2016-02-19 11:47:11 | Шерзод
У мануалах пишуть такий код:
date_sun_info (strtotime ( "2006-12-12"), 31.7667, 35.2333);
Якщо треба вивести схід / захід поточного дня, то не треба писати strtotime (date ( "Ymd")). Можна замінити функцією time (), так як strtotime ( "2006-12-12") все одно вставляє туди тимчасову мітку.
date_sun_info (time (), 31.7667, 35.2333); - думаю найкоротший код.
Якщо потрібна інфа про завтрашній день, то time () + 86400 секунд в добу (= 606024):
date_sun_info (time () + 86400, 31.7667, 35.2333);


2016-02-19 11:18:26 | Шерзод
Хотів доповнити для тих хто живе не в Росії. У мене функція date_sun_info () показував зовсім інші значення. Виявилося при установки веб-сервера в php.ini значення date.timezone за замовчуванням були "Europe / Moscow". Треба змінити на свій часовий пояс, в моєму випадку "Asia / Tashkent". Ті хто не хоче копатися в файлі настройки php.ini (так як для різних збірок вони можуть знаходиться в різних місцях), можуть прямо в початок скрипта додати ini_set ( 'date.timezone', "Asia / Tashkent");


2011-10-16 22:08:55 | САНЧО
Може допомогти програма RA4NCN


2011-03-11 21:08:35 | Олександр
На скільки я пам'ятаю - довгота москви 37градусов 37 хвилин, отже - в формулу треба підставляти 37.63 - ймовірно у Вас помилка.


2011-02-21 12:25:55 | Andrey_B
Олег, але ж ви маєте рацію. Дійсно в PHP5 є така функція.
Тільки ось розрахунок часу відрізняється від мого. На 2-4 хвилини. З метою автоматизації освітлення несуттєво, але цікаво чому.
Я перевіряв свою функцію на сайтах, присвячених астрономії і розрахунок збігався. Може бути хтось візьметься визначити? Яка з функцій - та що представлена ​​в статті або та, що закладена в PHP5 дає більш правильний результат?
А ось civil_twilight дійсно річ корисна. Якраз наш випадок;)
Спасибі за корисний коментар.


2011-02-21 11:59:55 | Олег
Велосипед? :)
/ru.php.net/manual/en/function.date-sun-info.php
повертає:
sunrise: 5:52:11
sunset: 15:41:21
transit: 10:46:46
civil_twilight_begin: 5:24:08
civil_twilight_end: 16:09:24
nautical_twilight_begin: 4:52:25
nautical_twilight_end: 16:41:06
astronomical_twilight_begin: 4:21:32
astronomical_twilight_end: 17:12:00
Цивільні сутінки (civil_twilight) швидше за все потрібні для включення-виключення освітлення.


Lt;?
Підкажіть, як цей функціонал додати в демо інтерфейс?
Може бути хтось візьметься визначити?
Яка з функцій - та що представлена ​​в статті або та, що закладена в PHP5 дає більш правильний результат?