Функция определения восхода/заката

Здесь выкладываем скрипты
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Моя новая функция определения восхода/заката FuncSunrise.
Работает с API ресурсом https://api.sunrise-sunset.org, которому нужно сообщить широту и долготу и дату (необязательный параметр, если не указан, используется сегодняшняя)
У кого есть модем c возможностью определения широты и долготы по GPRS, можно использовать функцию с автоопределением местоположения от модема.
Я использую FuncSunrise для организации освещения на дачном участке через управление интернет-модулями реле с Микротика.
Код не оптимизировал особо, работает и хорошо.

Код: Выделить всё

# Function Sunrise by Sertik 08/12/2020; correct bug 07/06/2022
# is used https://api.sunrise-sunset.org
# usial [$FuncSunrise "latitude" "longitude" "date (in format dd/mm/yyyy)"]

# may be usial globlal variable $FlagSunrise
# if FlagSunrise no set - usial works
# :global FlagSunrise "civil" - функция возвращает гражданский восход/закат
# :global FlagSunrise "nautical"  - морской/навигационный восход/закат
# :global FlagSunrise "astronomical" - астрономический


:global FuncSunrise do={
:global FlagSunrise
:local data;
:local convert 0;
:local dateM;
:local month;
:local month1
:local year;
:local day;
:local dateMik;
:local sunrise
:local meridiumsr
:local sunset
:local meridiumsn
:local srise

:if ([:len $3]=0) do={:set $data [/system clock get date]; :set $convert 1; :set $dateMik $data} else={:set $data $3}
:if ($convert=1) do={
:local mstr [:toarray {"jan"="01"; "feb"="02"; "mar"="03"; "apr"="04"; "may"="05"; "jun"="06"; "jul"="07"; "aug"="08"; "sep"="09"; "oct"="10"; "nov"="11"; "dec"="12"}]
:set dateM [:pick $data 0 3]
:set month ($mstr->$dateM)
:set month1 $month
:set year [:pick $data 7 11]
:set day [:pick $data 4 6]
} else={

:local mstr1 [:toarray {"01"="Jan"; "02"="Feb"; "03"="Mar"; "04"="Apr"; "05"="May"; "06"="Jun"; "07"="Jul"; "08"="Aug"; "09"="Sep"; "10"="Oct"; "11"="Nov"; "12"="Dec"}]
:set month ($mstr1->[:pick $data 3 5])
:set month1 [:pick $data 3 5]
:set year [:pick $data 6 10]
:set day [:pick $data 0 2]
:set dateMik ("$month/"."$day/"."$year")
}
:set data ("$year-"."$month1-"."$day")

#:do {
#/tool fetch url="https://api.sunrise-sunset.org/json?lat=$1&lng=$2&date=$data" mode=https keep-result=yes dst-path="sr.txt"} on-error={:return "ERROR"}
#:delay 2s;
#:local srise [/file get sr.txt contents]
#/file remove sr.txt

:local sri [/tool fetch url=("https://api.sunrise-sunset.org/json\?lat=$1&lng=$2&date=$data") mode=https as-value output=user];
:if ([:len $sri]=0) do={:log info $sri; :return "ERROR"}
:if (($sri->"status")!="finished") do={:return "ERROR"} else={:set $srise ($sri->"data")}

:global FlagSunrise;
:if (([:len $FlagSunrise]=0) or (!any $FlagSunrise)) do={
:set sunrise [:pick $srise ([find $srise "sunrise\":\""]+10) ([:find $srise "sunset"]-6)]
:set meridiumsr [:pick $srise ([find $srise "sunset"]-5) ([:find $srise "sunset"]-3)]
:set sunset [:pick $srise ([find $srise "sunset\":\""]+9) ([:find $srise "solar"]-6)]
:set meridiumsn [:pick $srise ([find $srise "solar"]-5) ([:find $srise "solar"]-3)]
}

:if ($FlagSunrise="civil") do={
:set sunrise [:pick $srise ([find $srise "civil_twilight_begin\":\""]+23) ([:find $srise "civil_twilight_end"]-6)]
:set meridiumsr [:pick $srise ([find $srise "civil_twilight_end"]-5) ([:find $srise "civil_twilight_end"]-3)]
:set sunset [:pick $srise ([find $srise "civil_twilight_end\":\""]+21) ([:find $srise "nautical_twilight_begin"]-6)]
:set meridiumsn [:pick $srise ([find $srise "nautical_twilight_begin"]-5) ([:find $srise "nautical_twilight_begin"]-3)]
}
:if ($FlagSunrise="nautical") do={
:set sunrise [:pick $srise ([find $srise "nautical_twilight_begin\":\""]+26) ([:find $srise "nautical_twilight_end"]-6)]
:set meridiumsr [:pick $srise ([find $srise "nautical_twilight_end"]-5) ([:find $srise "nautical_twilight_end"]-3)]
:set sunset [:pick $srise ([find $srise "nautical_twilight_end\":\""]+24) ([:find $srise "astronomical_twilight_begin"]-6)]
:set meridiumsn [:pick $srise ([find $srise "astronomical_twilight_begin"]-5) ([:find $srise "astronomical_twilight_begin"]-3)]
}
:if ($FlagSunrise="astronomical") do={
:set sunrise [:pick $srise ([find $srise "astronomical_twilight_begin\":\""]+30) ([:find $srise "astronomical_twilight_end"]-6)]
:set meridiumsr [:pick $srise ([find $srise "astronomical_twilight_end"]-5) ([:find $srise "astronomical_twilight_end"]-3)]
:set sunset [:pick $srise ([find $srise "astronomical_twilight_end\":\""]+28) ([:find $srise "status"]-7)]
:set meridiumsn [:pick $srise ([find $srise "status"]-6) ([:find $srise "status"]-4)]
}
:set FlagSunrise (:nothing)

:if ([:len $sunrise]=7) do={:set $sunrise ("0"."$sunrise")}
:if ([:len $sunset]=7) do={:set $sunset ("0"."$sunset")}

# correct bug 07/06/2022 [time but sunrise or sunset 12:ÕÕ:ÕÕ]
:if ([:pick $sunrise 0 2]="12") do={:set $sunrise ("00:"."$[:pick $sunrise 3 [:len $sunrise]]")}
:if ([:pick $sunset 0 2]="12") do={:set $sunset ("00:"."$[:pick $sunset 3 [:len $sunset]]")}

:global FuncEpochTime
:set $sunrise [$FuncEpochTime "nogmt" $dateMik $sunrise]
:set $sunrise ($sunrise+[/system clock get gmt-offset])
:global FuncUnixTimeToFormat
:local tsunrise [$FuncUnixTimeToFormat $sunrise "5"]
:if ($meridiumsr="PM") do={
:local tym [:pick $tsunrise ([:find $tsunrise "-"]+1) ([:find $tsunrise "-"]+3)]
:if ([:tonum $tym]<12) do={
:local tymsum [:tostr ([:tonum $tym]+12)];
:local start [:pick $tsunrise 0 [:find $tsunrise "-"]]
:local end [:pick $tsunrise ([:find $tsunrise "-"]+3) [:len $tsunrise]]
:set $tsunrise ("$start"."-"."$[:tostr ([:tonum $tym]+12)]"."$end")
  }
}
:set $sunset [$FuncEpochTime "nogmt" $dateMik $sunset]
:set $sunset ($sunset+[/system clock get gmt-offset])
:local tsunset [$FuncUnixTimeToFormat $sunset "5"]

:if ($meridiumsn="PM") do={
:local tym1 [:pick $tsunset ([:find $tsunset "-"]+1) ([:find $tsunset "-"]+3)]
:if ([:tonum $tym1]<12) do={
:local tymsum1 [:tostr ([:tonum $tym1]+12)];
:local start1 [:pick $tsunset 0 [:find $tsunset "-"]]
:local end1 [:pick $tsunset ([:find $tsunrise "-"]+3) [:len $tsunrise]]
:set $tsunset ("$start1"."-"."$[:tostr ([:tonum $tym1]+12)]"."$end1")
  }
}

:local sum [:toarray {"sunrise"=$tsunrise; "sunset"=$tsunset}]
:return $sum

}

# example Pereslavl-Zalesskiy
# https://api.sunrise-sunset.org/json?lat=56.5312&lng=38.5209

#:log info ""
#:log info "восход/закат"
#:local sr [$FuncSunrise "56.5312" "38.5209" "22/04/2020"]
#:log info $sr
#:delay 3s;
#:log info ""

#:log info "гражданский восход/закат"
#:global FlagSunrise "civil";
#:local sr [$FuncSunrise "56.5312" "38.5209" "16/10/2020"]
#:log info $sr

#:log info ""

#:log info "навигационный (морской) восход/закат"
#:global FlagSunrise "nautical";
#:local sr [$FuncSunrise "56.5312" "38.5209" "22/04/2020"]
#:log info $sr
#:delay 3s;

#:log info ""

#:log info "астрономический восход/закат"
#:global FlagSunrise "astronomical";
#:local sr [$FuncSunrise "56.5312" "38.5209" "22/04/2020"]
#:log info $sr

:local sr [$FuncSunrise "56.5312" "38.5209"]
:log info $sr
#:log info "only times"
#:local srtime [:totime [:pick ($sr->"sunrise") ([find ($sr->"sunrise") "-"]+1) [:len ($sr->"sunrise")]]]
#:log info $srtime
#:local sntime [:totime [:pick ($sr->"sunset") ([find ($sr->"sunset") "-"]+1) [:len ($sr->"sunset")]]]
#:log info $sntime
Для работы FuncSunrise необходима служебная функция FuncEpochTime, установленная в окружение переменных

Код: Выделить всё

# работа функции ограничена 2000-2199 гг.
# без параметров - возвращает timeStamp (UnixTime)
# c параметрами $1 - нужно учитывать gmt или нет
# возвращает UnixTime этой временной точки
# если $2 не задан - берется текущая дата из /system clock
# если $3 не задан - берется текущее время аналогично

:global FuncEpochTime do={
:local gmtofset 0
:local ds
:local ts
 :if ([:len $1]=0) do={:set gmtofset [/system clock get gmt-offset]} else={:set gmtofset 0}
 :if ($1="gmtoffset") do={:set gmtofset [/system clock get gmt-offset]} else={:set gmtofset 0}
 :if ($1="nogmt") do={:set gmtofset 0}
:if ($gmtofset!=0) do={
:if (($gmtofset >> 31) = 1) do={:set $gmtofset ($gmtofset - 4294967296);}
}

 :if ([:len $2]=0) do={:set ds [/system clock get date]} else={:set ds $2}
 :if ([:len $3]=0) do={:set ts [/system clock get time]} else={:set ts $3}

#   :local ds [/system clock get date];
   :local months;
   :if ((([:pick $ds 9 11]-1)/4) != (([:pick $ds 9 11])/4)) do={
      :set months {"an"=0;"eb"=31;"ar"=60;"pr"=91;"ay"=121;"un"=152;"ul"=182;"ug"=213;"ep"=244;"ct"=274;"ov"=305;"ec"=335};
   } else={
      :set months {"an"=0;"eb"=31;"ar"=59;"pr"=90;"ay"=120;"un"=151;"ul"=181;"ug"=212;"ep"=243;"ct"=273;"ov"=304;"ec"=334};
   }
:local year [:tonum [:pick $ds 7 9]]
   :set ds (([:pick $ds 9 11]*365)+(([:pick $ds 9 11]-1)/4)+($months->[:pick $ds 1 3])+[:pick $ds 4 6]);
#   :local ts [/system clock get time];
   :set ts (([:pick $ts 0 2]*60*60)+([:pick $ts 3 5]*60)+[:pick $ts 6 8]);
#   :return ($ds*24*60*60 + $ts + 946684800 - $gmtofset);
:if ($year=20) do={
   :return ($ds*24*60*60 + $ts + 946684800 - $gmtofset);}
:if ($year=21) do={
   :return (($ds-1)*24*60*60 + $ts + 4102444800 - $gmtofset);
} else={:return 0}
}
Также необходима функция FuncUnixTimeToFormat, созданная с использованием кода нашего уважаемого pepelxl

Код: Выделить всё

# год не ограничен текущим столетием
# usial [$FuncUnixTimeToFormat "timeStamp", "type"]

# type:

# "unspecified" - month/dd/yyyy <only> ((Mikrotik sheduller format)
# 1 - yyyy/mm/dd hh:mm:ss
# 2 - dd:mm:yyyy hh:mm:ss
# 3 - dd month yyy hh mm ss
# 4 - yyyy month dd hh mm ss
#5 - month/dd/yyyy-hh:mm:ss (Mikrotik sheduller format)

:global FuncUnixTimeToFormat do={
:local decodedLine ""
:local timeStamp $1

:local timeS ($timeStamp % 86400)
:local timeH ($timeS / 3600)
:local timeM ($timeS % 3600 / 60)
:set $timeS ($timeS - $timeH * 3600 - $timeM * 60)
:local dateD ($timeStamp / 86400)
:local dateM 2
:local dateY 1970
:local leap false
:while (($dateD / 365) > 0) do={
:set $dateD ($dateD - 365)
:set $dateY ($dateY + 1)
:set $dateM ($dateM + 1) 
:if ($dateM = 4) do={:set $dateM 0
:if (($dateY % 400 = 0) or ($dateY % 100 != 0)) do={:set $leap true
:set $dateD ($dateD - 1)}} else={:set $leap false}}
:local months [:toarray (0,31,28,31,30,31,30,31,31,30,31,30,31)]
:if (leap) do={:set $dateD ($dateD + 1); :set ($months->2) 29}
do {
:for i from=1 to=12 do={:if (($months->$i) > $dateD) do={:set $dateM $i; :set $dateD ($dateD + 1); break;} else={:set $dateD ($dateD - ($months->$i))}}
} on-error={}
:local tmod
:if ([:len $2]!=0) do={:set $tmod $2} else={:set $tmod (:nothing)}
:local s "/"
:local nf true
:local mstr {"jan";"feb";"mar";"apr";"may";"jun";"jul";"aug";"sep";"oct";"nov";"dec"}
:local strY [:tostr $dateY]
:local strMn
:local strD
:local strH
:local strM
:local strS
:if ($nf) do={
:if ($dateM > 9) do={:set $strMn [:tostr $dateM]} else={:set $strMn ("0".[:tostr $dateM])}
:if ($dateD > 9) do={:set $strD [:tostr $dateD]} else={:set $strD ("0".[:tostr $dateD])}
:if ($timeH > 9) do={:set $strH [:tostr $timeH]} else={:set $strH ("0".[:tostr $timeH])}
:if ($timeM > 9) do={:set $strM [:tostr $timeM]} else={:set $strM ("0".[:tostr $timeM])}
:if ($timeS > 9) do={:set $strS [:tostr $timeS]} else={:set $strS ("0".[:tostr $timeS])}
} else={
:set strMn [:tostr $dateM]
:set strD [:tostr $dateD]
:set strH [:tostr $timeH]
:set strM [:tostr $timeM]
:set strS [:tostr $timeS]
}
do {
:if ([:len $tmod]=0) do={:local mt ($mstr->($dateM - 1)); :set $decodedLine ("$mt/"."$strD/"."$strY"); break;}
:if ($tmod = 1) do={:set $decodedLine "$strY$s$strMn$s$strD $strH:$strM:$strS"; break;}
:if ($tmod = 2) do={:set $decodedLine "$strD$s$strMn$s$strY $strH:$strM:$strS"; break;}
:if ($tmod = 3) do={:set $decodedLine ("$strD ".($mstr->($dateM - 1))." $strY $strH:$strM:$strS"); break;}
:if ($tmod = 4) do={:set $decodedLine ("$strY ".($mstr->($dateM - 1))." $strD $strH:$strM:$strS"); break;}
:if ($tmod = 5) do={:local m ($mstr->($dateM - 1)); :set $decodedLine ("$m/"."$strD/"."$strY"."-$strH:$strM:$strS"); break;}

} on-error={}
:return $decodedLine;
}
Последний раз редактировалось Sertik 16 июн 2022, 20:22, всего редактировалось 6 раз.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

:set gmtofset [/system clock get gmt-offset]
Поставь в настройках роутера gmt с отрицательным значением и увидишь как разрабы в очередной раз обосрались.


Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Да, я уже видел эту ошибку. Вместо отрицательного значения GMT*60*60 там вываливается какое-то положительное умопомрачительное огромное число. Неужели они об этом не знают ?


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Знают, не знают, я хз. У меня отрицательный опыт общения с поддержкой. Вываливается там unsigned int 32 вместо signed. А спецификация в wiki определяет только num - signed 64. То есть выхлоп содержит двойную ошибку. Как лечить посмотри у меня в примере с sms.


Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Спасибо, но у тебя там искать очень долгою Ткни носом, пожалуйста, где посмотреть.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
pepelxl
Сообщения: 161
Зарегистрирован: 23 июл 2013, 18:47

Код: Выделить всё

:local offsetR [/system clock get gmt-offset]
:if (($offsetR >> 31) = 1) do={:set $offsetR ($offsetR - 4294967296);}
или

Код: Выделить всё

:local offsetR [/system clock get gmt-offset]
:if (($offsetR >> 31) = 1) do={:set $offsetR ($offsetR - 4294967296); :set $offsetR ($offsetR * -1)}
В зависимости , что вам нужно получить

В одно действие записать не получается, видимо работают какие то внутренние преобразования int.

И у вас плохой код в fetch. Надо сразу запихивать выхлоп в аргумент через as-value.
1) Если скрипт будет вызываться часто, то хана флеши.
2) ответ от сервера может быть больше 4KB, тогда будет потеря при записи оверхеда, а as-value аргумент лишен этой проблемы.


Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Спасибо. Насчет fetch я знаю, скрипт вызывается не часто. Хана флеши не будет. У меня подобные штуки работают уже пять лет и никакой ханы.
С as-value пока не получилось с этим ресурсом, но так лучше конечно, постараюсь сделать.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

По "велению" pepelx переделал вызов ресурса с " /tool fetch ... as-value output=user". Теперь за флешки можно не бояться, хотя им и так ничего бы не было.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

Функция UnixTimeToFormat ошибается в високосные годы в подсчете дат 30/31 чисел некоторых месяцев. Создателя pepelxl очень прошу исправить ошибку.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1598
Зарегистрирован: 15 сен 2017, 09:03

pepelxl большое спасибо. пока ошибка исправлена, посмотрим как будет дальше.
Кто качал функции нужно перекачать заново.


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Ответить