226 lines
7.6 KiB
PHP
226 lines
7.6 KiB
PHP
<?php
|
|
// -------------------------------------------
|
|
// outdoor lights control -- server
|
|
// copyright: Jannik Beyerstedt | https://jannikbeyerstedt.de
|
|
// license: http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 License
|
|
// -------------------------------------------
|
|
|
|
$config_filename = 'config_times.json';
|
|
$timeRegex = '/^((2[0-3]|1[0-9]|0[0-9]|[^0-9][0-9]):([0-5][0-9]|[0-9]))/';
|
|
$sunsetTrue = 90+50/60; /* "true" sunrise/ sunset */
|
|
$sunsetCivilian = 96; /* Civilian Twilight */
|
|
$sunsetNautical = 102; /* Nauticla Twilight */
|
|
|
|
$sun_zenith = 93; /* use one of the above $sunset* or own value */
|
|
$timezone = "Europe/Berlin";
|
|
|
|
class LightStatus {
|
|
public $state = true; /* current state: lights on/off */
|
|
public $changeTime = 1; /* minutes until next state change */
|
|
public $waitTime = 0; /* minutes the client should wait until next request */
|
|
|
|
public $times = null; /* config array */
|
|
|
|
public $sunrise, $sunset; /* time string hh:mm */
|
|
public $isNight; /* bool, true if it's at night */
|
|
|
|
function __construct() {
|
|
return $this->readTimes();
|
|
}
|
|
|
|
/* return string for the service API */
|
|
function __toString() {
|
|
return 's='.(int)$this->state.' t='.$this->waitTime;
|
|
}
|
|
|
|
/* re-calculate values, returns true if successful */
|
|
public function update($currentTime = null) {
|
|
global $sun_zenith;
|
|
global $timezone;
|
|
|
|
if (null == $currentTime) {
|
|
$currentTime = time();
|
|
}
|
|
|
|
$sunset = null;
|
|
$sunrise = null;
|
|
$times = [];
|
|
|
|
// calculate times
|
|
date_default_timezone_set($timezone);
|
|
$gmtOffset = date("Z") / (60*60);
|
|
|
|
if (($currentTime - strtotime("12:00")) > 0) {
|
|
// currentTime is in the evening
|
|
$this->sunset = date_sunset(time(), SUNFUNCS_RET_STRING, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
$this->sunrise = date_sunrise((time() + 24*60*60), SUNFUNCS_RET_STRING, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
|
|
$sunset = date_sunset(time(), SUNFUNCS_RET_TIMESTAMP, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
$sunrise = date_sunrise((time() + 24*60*60), SUNFUNCS_RET_TIMESTAMP, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
$timeKey = 'time'.$i;
|
|
|
|
$startTime = strtotime($this->times[$timeKey]['on']);
|
|
if ((strtotime("00:00")+24*60*60) - $startTime > 12*60*60) {
|
|
$startTime += 24*60*60;
|
|
}
|
|
$stopTime = strtotime($this->times[$timeKey]['off']);
|
|
if ((strtotime("00:00")+24*60*60) - $stopTime > 12*60*60) {
|
|
$stopTime += 24*60*60;
|
|
}
|
|
|
|
$times[] = ["on"=>$startTime, "off"=>$stopTime];
|
|
}
|
|
} else {
|
|
// currentTime is in the morning
|
|
$this->sunset = date_sunset((time() - 24*60*60), SUNFUNCS_RET_STRING, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
$this->sunrise = date_sunrise(time(), SUNFUNCS_RET_STRING, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
|
|
$sunset = date_sunset((time() - 24*60*60), SUNFUNCS_RET_TIMESTAMP, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
$sunrise = date_sunrise(time(), SUNFUNCS_RET_TIMESTAMP, $this->times['position']['lat'], $this->times['position']['long'], $sun_zenith, $gmtOffset);
|
|
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
$timeKey = 'time'.$i;
|
|
|
|
$startTime = strtotime($this->times[$timeKey]['on']);
|
|
if ($startTime - strtotime("00:00") > 12*60*60) {
|
|
$startTime -= 24*60*60;
|
|
}
|
|
$stopTime = strtotime($this->times[$timeKey]['off']);
|
|
if ($stopTime - strtotime("00:00") > 12*60*60) {
|
|
$stopTime -= 24*60*60;
|
|
}
|
|
|
|
$times[] = ["on"=>$startTime, "off"=>$stopTime];
|
|
}
|
|
}
|
|
|
|
// -- first check, if an instant-on time is set --
|
|
if ($this->times['instant-on'] != null) {
|
|
if ($this->times['instant-on'] > time()) {
|
|
$this->state = true;
|
|
$this->changeTime = (int)(($this->times['instant-on']-time())/60);
|
|
$this->waitTime = $this->changeTime;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
// reset instant-on
|
|
$this->state = false;
|
|
$this->times['instant-on'] = null;
|
|
$this->saveTimes();
|
|
}
|
|
}
|
|
|
|
// -- if no instant-on time is set, follow normal conditions --
|
|
if ($sunset < $currentTime && $sunrise > $currentTime) {
|
|
$this->isNight = true;
|
|
|
|
// it's night: check, if we are in one of the time intervals
|
|
$this->changeTime = null;
|
|
foreach ($times as $t) {
|
|
if ($t["on"] < $currentTime && $t["off"] > $currentTime) {
|
|
// we are in this interval
|
|
$this->state = true;
|
|
$this->changeTime = (int)(($t["off"] - $currentTime) / 60);
|
|
$this->waitTime = 1;
|
|
return true;
|
|
} else if ($t["on"] > $currentTime) {
|
|
// we are right before this interval
|
|
$this->state = false;
|
|
$this->changeTime = (int)(($t["on"] - $currentTime) / 60);
|
|
$this->waitTime = 1;
|
|
return true;
|
|
}
|
|
// otherwise we are after this interval, but potentioally before next interval
|
|
}
|
|
|
|
if ($this->changeTime == null) {
|
|
// we are after the last interval, so changeTime is not set yet
|
|
$this->state = false;
|
|
$this->changeTime = (int)(($sunrise - $currentTime) / 60);
|
|
$this->waitTime = $this->changeTime;
|
|
return true;
|
|
}
|
|
|
|
} else if ($currentTime > $sunrise || $sunset > $currentTime) {
|
|
$this->isNight = false;
|
|
|
|
// it's day: nothing else to check
|
|
$this->state = false;
|
|
$this->changeTime = (int)(($sunset - $currentTime) / 60);
|
|
if ($this->changeTime < 0) {
|
|
$this->changeTime += 24*60; // changeTime is in Minutes
|
|
}
|
|
$this->waitTime = $this->changeTime;
|
|
return true;
|
|
|
|
} else {
|
|
echo "ERROR: invalid time of day.";
|
|
return 'ERROR';
|
|
}
|
|
}
|
|
|
|
/* save modified $times array to config file, returns true if successful */
|
|
public function saveTimes() {
|
|
global $config_filename;
|
|
|
|
if (empty($this->times)) {
|
|
return 'ERROR';
|
|
} else {
|
|
$json_string = json_encode($this->times, JSON_PRETTY_PRINT);
|
|
file_put_contents($config_filename, $json_string);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public function setClientLastSeen() {
|
|
$this->times['clientLastSeen'] = time();
|
|
$this->saveTimes();
|
|
}
|
|
public function getClientLastSeen() {
|
|
return $this->times['clientLastSeen'];
|
|
}
|
|
|
|
|
|
|
|
private function readTimes() {
|
|
global $config_filename;
|
|
|
|
$file_content = file_get_contents($config_filename);
|
|
if ($file_content == FALSE) {
|
|
return 'ERROR';
|
|
} else {
|
|
$this->times = json_decode($file_content, true);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function checkTimesInput($times) {
|
|
global $timeRegex;
|
|
|
|
if (!isset($_POST['time1-start']) || !preg_match($timeRegex, $_POST['time1-start'])) {
|
|
return "time1-start not valid";
|
|
}
|
|
if (!isset($_POST['time1-stop']) || !preg_match($timeRegex, $_POST['time1-stop'])) {
|
|
return "time1-stop not valid";
|
|
}
|
|
if (!isset($_POST['time2-start']) || !preg_match($timeRegex, $_POST['time2-start'])) {
|
|
return "time2-start not valid";
|
|
}
|
|
if (!isset($_POST['time2-stop']) || !preg_match($timeRegex, $_POST['time2-stop'])) {
|
|
return "time2-stop not valid";
|
|
}
|
|
if (!isset($_POST['time3-start']) || !preg_match($timeRegex, $_POST['time3-start'])) {
|
|
return "time3-start not valid";
|
|
}
|
|
if (!isset($_POST['time3-stop']) || !preg_match($timeRegex, $_POST['time3-stop'])) {
|
|
return "time3-stop not valid";
|
|
}
|
|
return true;
|
|
}
|
|
?>
|