namespace VDV\Alarm\Model; use VDV\Alarm\Task\Alarm as AlarmTask; use VDV\Log\Model; use VDV\Core\Model\MailDb; use PDO; use DateTime; use VDV\datasource_csi\Task\SendCommand; use VDV\TaskMgr\Model\Task; use VDV\TaskMgr\Model\TaskLogger; class AlarmEvaluator { private $db, $db_type; public $bulkAlarmDb; public $evalMath; public $customAlarmDb; public $data = array(); public $emailBulk = array(); public $logger; public $taskLogger; public $mailDb; public function __construct($taskLogger) { global $db, $db_type; $this->db =& $db; $this->db_type =& $db_type; $this->bulkAlarmDb = new BulkAlarmDb(); $this->customAlarmDb = new CustomAlarmDb(); $this->logger = new model\Logger(); $this->evalMath = new EvalMath(); $this->mailDb = new MailDb(); $this->taskLogger = $taskLogger; } public function run() { $this->checkRepeatAlarms(); } public function checkMultiConditionalAlarm() { $multiConditionalAlarm = $this->customAlarmDb->getAllActiveMultiConditionalAlarms(); $this->evaluateMultiConditionalAlarms($multiConditionalAlarm); } public function checkCustomAlarms() { $customAlarms = $this->bulkAlarmDb->getCustomAlarms(); $this->getDataForBulkAlarm($customAlarms); $this->evaluateAlarms($customAlarms); } public function checkBulkAlarms() { $bulkAlarms = $this->getBulkAlarms(); $groups = $this->splitAllBulksIntoGroups($bulkAlarms); foreach ($groups as $group) { $this->taskLogger->log(Task::LOG_INFO, AlarmTask::MSG_HANDLER_ID, [$group[0]["groupId"]]); $this->sortBulkAlarms($group); $this->getDataForBulkAlarm($group); $this->evaluateAlarms($group); $this->data = []; } } public function checkRepeatAlarms() { $this->checkMultiConditionRepeatAlarms(); $alarms = $this->bulkAlarmDb->getRepeatAlarmsAndOnOffString(); foreach ($alarms as $alarm) { $this->sendAlarmMessage($alarm, 1, 0); $this->bulkAlarmDb->updateLastRepeatTimestamp($alarm["active_alarm_id"]); } } public function checkMultiConditionRepeatAlarms() { $alarms = $this->customAlarmDb->getAllRepeatMultiConditionAlarms(); foreach ($alarms as $alarm) { $conditions = $alarm["conditions"]; $startAndStopTimes = $this->getUniqueVariableIdsAndStartAndStopTime($conditions); $stopTime = $alarm["alarm_timestamp"]; $startTime = new DateTime($stopTime); $startTime = $startTime->modify("-1 second"); $startTime = $startTime->format("Y-m-d H:i:s"); foreach ($startAndStopTimes as $key => &$startAndStopTime) { $startAndStopTimes[$key]["variable_id"] = $startAndStopTime["variableId"]; $startStopTime["start"] = $startTime; $startStopTime["stop"] = $stopTime; } $data = $this->getDataForMultiConditions($conditions, $startAndStopTimes); $conditionMessage = ''; foreach ($conditions as $key => $condition) { $variableId = $condition["variable_id"]; $alarmType = $condition["limit_type"]; $alarmValue = $condition["limit_value"]; $alarmTypeString = $this->getLimitCondition($alarmType); $variableData = $data[$variableId]; $timestampIndex = array_search($stopTime, $variableData["variable_time"]); $value = $variableData["variable_value"][$timestampIndex]; $alarmOn = true; $conditionMessage .= $this->makeMessageStringFromCondition($alarm, $condition, $value, $alarmTypeString, $alarmValue, $key); } $alarm["message"] = str_replace("$CONDITION$", $conditionMessage, $alarm["message"]); $this->sendAlarmMessage($alarm, 1, 0); $this->bulkAlarmDb->updateLastRepeatTimestamp($alarm["active_alarm_id"]); } } public function getBulkAlarms() { return $this->bulkAlarmDb->getAllBulkAlarms(); } public function splitAllBulksIntoGroups($bulkAlarms) { $group = []; $allGroupIds = array_unique(array_map(function ($alarm) { return $alarm["groupId"]; }, $bulkAlarms)); foreach ($allGroupIds as $groupId) { $inGroup = array_filter($bulkAlarms, function ($alarm) use($groupId) { return $alarm["groupId"] == $groupId; }); array_push($group, array_values($inGroup)); } return $group; } public function getDataForBulkAlarm(array $bulkAlarm) { $allUniqueVarAndStartStop = $this->getUniqueVariableIdsAndStartAndStopTime($bulkAlarm); foreach ($allUniqueVarAndStartStop as $item) { $variableId = $item["variableId"]; $start = $item["start"]; $stop = $item["stop"]; $variableData = $this->getDataForVariable($variableId, $start, $stop); $this->data[$variableId] = $variableData; } } public function getUniqueVariableIdsAndStartAndStopTime(array $bulkAlarm) { $set = []; foreach ($bulkAlarm as $alarm) { if ($alarm["latest"] == 0) { continue; } $variableId = $alarm["variable_id"]; $start = $alarm["last_timestamp_check"]; $index = in_array($variableId, array_column($set, "variableId")); if (!$index) { $set[] = ["variableId" => $variableId, "start" => $start, "stop" => $this->getLatestTimestampForAlarm($alarm)]; } else { $tmp = $set[$index]; if ($start < $tmp["start"]) { $set[$index]["start"] = $start; } } } return $set; } private function getLatestTimestampForAlarm(array $alarm) { if ($alarm["calculated_variable"]) { $timestamp = $this->bulkAlarmDb->getColumn("
\xa SELECT MIN(file_path.last_timestamp)\xd\xa FROM variable_info
\xa JOIN file_path ON
\xa file_path.station_id = variable_info.station_id\xd
WHERE
variable_info.variable_id IN (\xd
SELECT variable_calculation_references.referenced_variable_id
\xa FROM variable_calculation_references\xd
WHERE\xd
variable_calculation_references.variable_id = :variable_id\xd
)", [":variable_id" => $alarm["variable_id"]]); } else { $timestamp = $this->bulkAlarmDb->getMaxTimestampFromStationId($alarm["station_id"]); } if (!$timestamp) { return ''; } $dateTime = new DateTime($timestamp); return $dateTime->modify("+ SECOND")->format("Y-m-d H:i:s"); } public function getDataForVariable(int $variableId, string $start, string $stop) { $result = get_vdv_data($this->db, $this->db_type, array($variableId), $start, $stop, 0, 0, 0, [], [], array(), 0, array(), array(), array()); return $result[0]; } public function getSummaryData(int $variableId, string $timestamp, int $periodHours, int $alarmProcess) { $stop = new DateTime($timestamp); $start = new DateTime($timestamp); $start->modify("-" . $periodHours . " Hours"); if ($alarmProcess == 3) { $stop->modify("+1 SECOND"); } else { $start->modify("+1 SECOND"); $stop->modify("+1 SECOND"); } $start = $start->format("Y-m-d H:i:s"); $stop = $stop->format("Y-m-d H:i:s"); $result = get_vdv_data($this->db, $this->db_type, [$variableId], $start, $stop, 0, 0, 0, [0], [0], [], 0, [], [], []); return $result[0]; } public function sortBulkAlarms(array &$bulkAlarms) { array_multisort(array_column($bulkAlarms, "variable_id"), SORT_ASC, $bulkAlarms); } public function calculateAlarmData($variableValueData, int $processType, int $abs) { if ($variableValueData == null) { return false; } $variableValueData = array_filter($variableValueData, function ($v, $k) { return $v !== null; }, ARRAY_FILTER_USE_BOTH); if ($variableValueData === null || count($variableValueData) === 0) { return false; } $processedValue = 0; if ($processType === 1) { $processedValue = array_sum($variableValueData) / count($variableValueData); } else { if ($processType === 2) { $processedValue = array_sum($variableValueData); } else { if ($processType === 3) { $first = end($variableValueData); $last = reset($variableValueData); $ROC = $first - $last; $processedValue = $abs ? abs($ROC) : $ROC; } else { if ($processType === 4) { asort($variableValueData); $variableValueData = array_values($variableValueData); $numOfValues = count($variableValueData); $medianPoint = floor(($numOfValues - 1) / 2); if ($numOfValues % 2 == 0) { $lowerMiddle = $variableValueData[$medianPoint]; $higherMiddle = $variableValueData[$medianPoint + 1]; $processedValue = ($lowerMiddle + $higherMiddle) / 2; } else { $processedValue = $variableValueData[$medianPoint]; } } } } } return $processedValue; } public function checkIfTimestampIsWithinTimeConditions($alarm, $timestamp) { $timestampHourMin = new DateTime($timestamp); $currentHour = $timestampHourMin->format("Hi"); $currentDayNumber = $timestampHourMin->format("N"); $alarmDays = explode(",", $alarm["days"]); $startTime = str_replace(":", '', $alarm["startTime"]); $stopTime = str_replace(":", '', $alarm["stopTime"]); $hasSmeDay = array_search($currentDayNumber, $alarmDays); if ($hasSmeDay !== false && $startTime == $stopTime) { return true; } else { if ($hasSmeDay !== false && $startTime > $stopTime) { if ($currentHour > $startTime || $currentHour <= $stopTime) { return true; } } else { if ($hasSmeDay !== false && $currentHour > $startTime && $currentHour <= $stopTime) { return true; } } } return false; } public function evaluateAlarms($alarms) { foreach ($alarms as $alarm) { $this->evaluateAlarm($alarm); } } public function evaluateAlarm(array $alarm) { $this->getDataForBulkAlarm([$alarm]); $latest = (int) $alarm["latest"]; if ($latest === 1) { $this->evaluateAlarmTypeLatest($alarm); } else { $this->evaluateAlarmTypeSummary($alarm); } } public function evaluateMultiConditionalAlarms(array $alarms) { foreach ($alarms as &$alarm) { $conditions = $alarm["conditions"]; $allStartAndStopTime = $this->getUniqueVariableIdsAndStartAndStopTime($conditions); $conditionsData = $this->getDataForMultiConditions($conditions, $allStartAndStopTime); $allHasData = $this->checkIfAllConditionsHaveData($conditions, $conditionsData); if ($allHasData === false) { continue; } $allTimestamps = $this->groupAllTheUniqueTimestampInOneGroup($conditionsData); $matchingTimestamps = $this->findACommonTimestampsForAllConditions($allTimestamps, $conditionsData); if (empty($matchingTimestamps)) { continue; } if (isset($alarm["isRollingAlarm"]) && $alarm["isRollingAlarm"] == 1) { $this->evaluateAlarmTypeMultiConditionRollingAlarm($alarm, $matchingTimestamps); } else { $this->evaluateAlarmTypeMultiCondition($alarm, $matchingTimestamps, $conditionsData); } } } public function evaluateAlarmTypeMultiConditionRollingAlarm($alarm, $matchingTimestamps) { $conditions = $alarm["conditions"]; $message = $alarm["message"]; foreach ($matchingTimestamps as $matchingTimestamp) { $summaryType = intval($conditions[0]["rollingDataType"]); if ($summaryType > 0 && $this->checkIfTimestampIsWholeHour($matchingTimestamp) === false) { continue; } $rollingHours = $conditions[0]["rollingHours"]; $exceedanceHours = $conditions[0]["exceedanceHours"]; $allVariableIds = array_column($conditions, "variable_id"); $summary = intval($conditions[0]["rollingPeriod"]); $startStopTime = $this->getRollingAlarmStartAndStopTimes($matchingTimestamp, $rollingHours, $summaryType); $data = $this->getDataForRollingAlarmVariable($allVariableIds, $startStopTime["start"], $startStopTime["stop"], $summary, $summaryType); $allUniqueTimestamps = $this->groupAllTheUniqueTimestampInOneGroup($data); $conditionMatchingTimestamps = $this->findACommonTimestampsForAllConditions($allUniqueTimestamps, $data); $exceedanceCount = 0; $numberOfMeasurementsInHour = $summaryType === 0 ? $this->getNumberOfMeasurementsInOneHour($conditionMatchingTimestamps) : 1; foreach ($conditionMatchingTimestamps as $conditionMatchingTimestamp) { $equationBuilder = []; $conditionMessage = ''; foreach ($conditions as $key => $condition) { $alarmType = $condition["limit_type"]; $variableId = $condition["variable_id"]; $variableKey = array_search($variableId, array_column($data, "variable_id")); $variableData = $data[$variableKey]; $timestampIndex = array_search($conditionMatchingTimestamp, $variableData["variable_time"]); $value = $variableData["variable_value"][$timestampIndex]; $alarmValue = $condition["limit_value"]; $alarmTypeString = $this->getLimitCondition($alarmType); $alarmOn = $this->checkCondition($value, $alarmValue, $alarmTypeString); if ($value === null || strtolower($value) === "nan") { $alarmOn = false; } $conditionProperties = ["alarmOn" => $alarmOn, "condition" => $condition["conditionOperator"], "parentheses" => $condition["parentheses"]]; array_push($equationBuilder, $conditionProperties); } if (count($conditions) == 1) { $alarmState = $alarmOn; } else { $equationString = $this->generateEquationString($equationBuilder); $alarmState = $this->evaluateEquationString($equationString); } if ($alarmState === true) { $exceedanceCount += 1; } } $alarmOn = $this->evaluateExceedanceForCondition($numberOfMeasurementsInHour, $exceedanceHours, $exceedanceCount, $summaryType); $dataType = $this->getStringForRollingAlarmDataType($summaryType); $overUnder = $alarmOn === true ? "over" : "under"; $alarm["message"] = str_replace("$OVER_UNDER$", $overUnder, $alarm["message"]); $alarm["message"] = str_replace("$ROLLING_HOURS$", $rollingHours, $alarm["message"]); $alarm["message"] = str_replace("$DATA_TYPE$", $dataType, $alarm["message"]); $alarm["message"] = str_replace("$EXCEEDANCE_HOURS$", $exceedanceHours, $alarm["message"]); if ($alarmOn === true) { $this->triggerAlarm($alarm, "0", $matchingTimestamp); } else { $this->disableAlarm($alarm, "0", $matchingTimestamp); } $this->updateLastTimestampCheckForMultiConditions($conditions, $matchingTimestamp); } } public function getRollingAlarmStartAndStopTimes($timestamp, $rollingHours, $summaryType) { $stop = new DateTime($timestamp); $stop->modify("+ 1 SECOND"); $stop = $stop->format("Y-m-d H:i:s"); $start = new DateTime($timestamp); $start->modify("- " . $rollingHours . " hours"); if ($summaryType === 0) { $start->modify("+ 1 SECOND"); } $start = $start->format("Y-m-d H:i:s"); return ["start" => $start, "stop" => $stop]; } public function checkIfTimestampIsWholeHour($timestamp) { $date = new DateTime($timestamp); $minutes = $date->format("i"); if ($minutes === "") { return true; } else { return false; } } public function getStringForRollingAlarmDataType(int $id) { $text = ''; if ($id === 1) { $text = "Average"; } else { if ($id === 2) { $text = "Sum"; } else { if ($id === 3) { $text = "Max"; } else { if ($id === 4) { $text = "Min"; } } } } return $text; } public function getNumberOfMeasurementsInOneHour($timestamps) { $maxCount = 9; $diff = 1; for ($i = 1; $i < count($timestamps); $i++) { if ($i === $maxCount) { break; } $prev = new DateTime($timestamps[$i - 1]); $curr = new DateTime($timestamps[$i]); $interval = $prev->diff($curr); if ($i === 1) { $hour = intval($interval->format("%h")); if ($hour === 0) { $diff = $interval->format("%i"); } else { if ($hour === 1) { $diff = 60; } } } } $numberOfMeasurementsInOneHour = intval(60 / $diff); return $numberOfMeasurementsInOneHour; } public function evaluateExceedanceForCondition($valuesPerHour, $exceedanceHours, $exceedanceCount, $summaryType) { if ($summaryType > 0) { $hoursOverLimit = $exceedanceCount; } else { $hoursOverLimit = $exceedanceCount / $valuesPerHour; } $conditionOn = $hoursOverLimit > $exceedanceHours; return $conditionOn; } public function getDataForRollingAlarmVariable($variableIds, $start, $stop, $summary, $summaryType) { $result = get_vdv_data($this->db, $this->db_type, $variableIds, $start, $stop, 0, 0, 0, [$summary], [$summaryType], array(), 0, array(), array(), array()); return $result; } public function getDataForMultiConditions($conditions, $startAndStopTimes) { $data = []; foreach ($conditions as $condition) { $variableId = $condition["variable_id"]; $startAndStopIndex = array_search($variableId, array_column($startAndStopTimes, "variableId")); $startAndStop = $startAndStopTimes[$startAndStopIndex]; $start = $startAndStop["start"]; $stop = $startAndStop["stop"]; $data[$variableId] = $this->getDataForVariable($variableId, $start, $stop); } return $data; } public function checkIfAllConditionsHaveData($conditions, $conditionData) { $allContain = true; foreach ($conditions as $condition) { $variableId = $condition["variable_id"]; if (!isset($conditionData[$variableId])) { $allContain = false; break; } if (empty($conditionData[$variableId]["variable_value"])) { $allContain = false; break; } } return $allContain; } public function groupAllTheUniqueTimestampInOneGroup($conditionsData) { $uniqueTimestamps = []; $index = 0; foreach ($conditionsData as $data) { $timestamps = $data["variable_time"]; foreach ($timestamps as $timestamp) { if (array_key_exists($timestamp, $uniqueTimestamps) === false) { $uniqueTimestamps[$timestamp] = $index; $index++; } } } return array_flip($uniqueTimestamps); } public function findACommonTimestampsForAllConditions($allUniqueTimestamps, $conditionsData) { $commonTimestamps = []; $numberOfConditions = count($conditionsData); $timestampArray = []; $index = 0; foreach ($allUniqueTimestamps as $timestamp) { $matchingTimestamps = 0; foreach ($conditionsData as $data) { $variableId = $data["variable_id"]; if (!isset($timestampArray[$variableId])) { $timestampArray[$variableId] = array_flip($data["variable_time"]); } $exists = array_key_exists($timestamp, $timestampArray[$variableId]); if ($exists !== false) { ++$matchingTimestamps; } else { continue 2; } } if ($matchingTimestamps === $numberOfConditions) { if (array_key_exists($timestamp, $commonTimestamps) === false) { $commonTimestamps[$timestamp] = $index; $index++; } } } return array_flip($commonTimestamps); } public function evaluateEquationString(string $equationString) { $alarmOn = $this->evalMath->evaluate($equationString); return $alarmOn === 1 ? true : false; } public function generateEquationString(array $equationProperties) { $numOfProperties = count($equationProperties); $equationString = ''; foreach ($equationProperties as $key => $property) { $openString = ''; $closeString = ''; $alarmOn = $property["alarmOn"]; $operator = $property["condition"] == "AND" ? "&" : "|"; $conditionState = $alarmOn === true ? 1 : 0; $openParenCount = substr_count($property["parentheses"], "("); $closeParenCount = substr_count($property["parentheses"], ")"); $openString = str_repeat("(", $openParenCount); $closeString = str_repeat(")", $closeParenCount); if ($key === 0) { $equationString = $openString . $conditionState . $closeString . " "; } else { if ($key == $numOfProperties - 1) { $equationString .= $operator . " " . $openString . $conditionState . $closeString; } else { $equationString .= $operator . " " . $openString . $conditionState . $closeString . " "; } } } return $equationString; } public function evaluateAlarmTypeMultiCondition(&$alarm, $matchingTimestamps, $conditionData) { $conditions = $alarm["conditions"]; $message = $alarm["message"]; foreach ($matchingTimestamps as $timestamp) { $equationBuilder = []; $alarm["message"] = $message; $conditionMessage = ''; foreach ($conditions as $key => $condition) { $variableId = $condition["variable_id"]; $alarmType = $condition["limit_type"]; $alarmValue = $condition["limit_value"]; $alarmTypeString = $this->getLimitCondition($alarmType); $variableData = $conditionData[$variableId]; $timestampIndex = array_search($timestamp, $variableData["variable_time"]); $value = $variableData["variable_value"][$timestampIndex]; if ($value === null || strtolower($value) === "nan") { $alarmOn = null; break; } $alarmOn = $this->checkCondition($value, $alarmValue, $alarmTypeString); $conditionMessage .= $this->makeMessageStringFromCondition($alarm, $condition, $value, $alarmTypeString, $alarmValue, $key); $conditionProperties = ["alarmOn" => $alarmOn, "condition" => $condition["conditionOperator"], "parentheses" => $condition["parentheses"]]; array_push($equationBuilder, $conditionProperties); } $alarm["message"] = str_replace("$CONDITION$", $conditionMessage, $alarm["message"]); if (count($conditions) == 1 || $alarmOn === null) { $alarmState = $alarmOn; } else { $equationString = $this->generateEquationString($equationBuilder); $alarmState = $this->evaluateEquationString($equationString); } if ($alarmState === null) { } else { if ($alarmState === true) { $this->triggerAlarm($alarm, "0", $timestamp); } else { $this->disableAlarm($alarm, "0", $timestamp); } } $this->updateLastTimestampCheckForMultiConditions($conditions, $timestamp); } } public function makeMessageStringFromCondition(&$alarm, $condition, $value, $alarmTypeString, $alarmValue, $key) { $conditionString = ''; $openParenCount = substr_count($condition["parentheses"], "("); $closeParenCount = substr_count($condition["parentheses"], ")"); $openString = str_repeat("(", $openParenCount); $closeString = str_repeat(")", $closeParenCount); $siteAndVar = $condition["station_name"] . ": " . $condition["english_name"] . " (" . $value . ") " . $alarmTypeString . " " . $alarmValue; $numOfConditions = count($alarm["conditions"]); if ($key === 0) { $conditionString .= $openString . $siteAndVar . $closeString . " "; } else { if ($key == $numOfConditions - 1) { $conditionString .= $condition["conditionOperator"] . " " . $openString . $siteAndVar . $closeString; } else { $conditionString .= $condition["conditionOperator"] . " " . $openString . $siteAndVar . $closeString . " "; } } return $conditionString; } public function updateLastTimestampCheckForMultiConditions(array $conditions, $timestamp) { foreach ($conditions as $condition) { $this->bulkAlarmDb->updateLastTimestampCheck($condition["alarm_condition_id"], $timestamp); } } public function evaluateAlarmTypeSummary(array $alarm) { $variableId = $alarm["variable_id"]; $lastRun = $alarm["last_timestamp_check"]; $stationId = $alarm["station_id"]; $latestTimestamp = $this->getLatestTimestampForAlarm($alarm); $allTimestamps = $this->getDataForVariable($variableId, $lastRun, $latestTimestamp); if (!is_array($allTimestamps["variable_time"])) { $allTimestamps["variable_time"] = []; } $alarmType = $alarm["limit_type"]; $alarmValue = $alarm["limit_value"]; $alarmTypeString = $this->getLimitCondition($alarmType); $numberOfValues = count($allTimestamps["variable_time"]); $lastTimeRunIndex = array_search($lastRun, $allTimestamps["variable_time"]); if ($lastTimeRunIndex === false) { if ($lastRun < $allTimestamps["variable_time"][0]) { $lastTimeRunIndex = -1; } } $alarmOn = false; for ($i = $lastTimeRunIndex + 1; $i < $numberOfValues; $i++) { $nextTimestamp = $allTimestamps["variable_time"][$i]; $periodHours = $alarm["period_hours"]; $alarmProcess = $alarm["process"]; $absoluteValue = $alarm["absolute_value"]; $isWithInRange = true; if (isset($alarm["timeAlarm"]) && $alarm["timeAlarm"] == 1) { $isWithInRange = $this->checkIfTimestampIsWithinTimeConditions($alarm, $nextTimestamp); if ($isWithInRange === false) { $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); continue; } } $data = $this->getSummaryData($variableId, $nextTimestamp, $periodHours, $alarmProcess); $summaryDataValue = $this->calculateAlarmData($data["variable_value"], $alarmProcess, $absoluteValue); if ($summaryDataValue === false) { $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); continue; } if ($alarm["compare_type"] == 1) { $alarmValue = $this->getValueForCompareVariable($alarm, $nextTimestamp); $alarm["limit_value"] = $alarmValue; } if ($alarmValue === false) { $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); continue; } $alarmOn = $this->checkCondition($summaryDataValue, $alarmValue, $alarmTypeString); if ($alarmOn === true) { $this->triggerAlarm($alarm, $summaryDataValue, $nextTimestamp); } else { $this->disableAlarm($alarm, $summaryDataValue, $nextTimestamp); } $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); } } public function getValueForCompareVariable($alarm, $timestamp) { $latest2 = $alarm["latest_2"]; $variableId2 = $alarm["variable_id_2"]; $periodHours2 = $alarm["period_hours_2"]; $alarmProcess2 = intval($alarm["process_2"]); $absoluteValue2 = $alarm["absolute_value_2"]; if ($latest2 == 1) { $start = $timestamp; $stop = new DateTime($timestamp); $stop->modify("+1 SECOND"); $stop = $stop->format("Y-m-d H:i:s"); $data = $this->getDataForVariable($variableId2, $start, $stop); if (!is_array($data["variable_time"])) { return false; } $index2 = array_search($timestamp, $data["variable_time"]); $alarmValue = $index2 !== false ? $data["variable_value"][$index2] : false; } else { $variableData2 = $this->getSummaryData($variableId2, $timestamp, $periodHours2, $alarmProcess2); $alarmValue = $this->calculateAlarmData($variableData2["variable_value"], $alarmProcess2, $absoluteValue2); } if ($alarmValue !== false) { $alarmValue += $alarm["offset_2"]; } return $alarmValue; } public function evaluateAlarmTypeLatest($alarm) { $variableId = $alarm["variable_id"]; $lastRun = $alarm["last_timestamp_check"]; $alarmType = $alarm["limit_type"]; $alarmValue = $alarm["limit_value"]; $alarmTypeString = $this->getLimitCondition($alarmType); $variableData = $this->data[$variableId]; if (!is_array($variableData["variable_time"])) { $variableData["variable_time"] = []; } $numberOfValues = count($variableData["variable_time"]); $lastTimeRunIndex = array_search($lastRun, $variableData["variable_time"]); if ($lastTimeRunIndex === false) { if ($lastRun < $variableData["variable_time"][0]) { $lastTimeRunIndex = -1; } } $alarmOn = false; for ($i = $lastTimeRunIndex + 1; $i < $numberOfValues; $i++) { $nextTimestamp = $variableData["variable_time"][$i]; $value = $variableData["variable_value"][$i]; $isWithInRange = true; if (isset($alarm["timeAlarm"]) && $alarm["timeAlarm"] == 1) { $isWithInRange = $this->checkIfTimestampIsWithinTimeConditions($alarm, $nextTimestamp); } if ($value === null || $isWithInRange === false) { $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); continue; } if ($alarm["compare_type"] == 1) { $alarmValue = $this->getValueForCompareVariable($alarm, $nextTimestamp); $alarm["limit_value"] = $alarmValue; } if ($alarmValue === false) { $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); continue; } $alarmOn = $this->checkCondition($value, $alarmValue, $alarmTypeString); if ($alarmOn === true) { $this->triggerAlarm($alarm, $value, $nextTimestamp); } else { $this->disableAlarm($alarm, $value, $nextTimestamp); } $this->bulkAlarmDb->updateLastTimestampCheck($alarm["alarm_condition_id"], $nextTimestamp); } } public function checkCondition($value, $alarmValue, $limitType) { $alarm = false; switch ($limitType) { case "<": $alarm = $value < $alarmValue; break; case "<=": $alarm = $value <= $alarmValue; break; case "=": $alarm = $value == $alarmValue; break; case ">=": $alarm = $value >= $alarmValue; break; case ">": $alarm = $value > $alarmValue; break; default: break; } return $alarm; } public function getLimitConditions() { return array("1" => "<", "2" => "<=", "3" => "=", "4" => ">=", "5" => ">"); } public function getLimitCondition(int $limitType) { $limitConditions = $this->getLimitConditions(); return $limitConditions[$limitType]; } public function triggerAlarm(&$alarm, $value, $timestamp) { if ($value === "NaN") { return; } $alarmId = $alarm["alarm_id"]; $delayTimestampPassed = true; $exists = $this->bulkAlarmDb->getActiveAlarm($alarmId); if (isset($alarm["multiCondition"]) && $alarm["multiCondition"] == 1) { $delay = $alarm["conditions"][0]["delay"]; $delayTimestamp = $alarm["conditions"][0]["delayTimestamp"]; } else { $delay = $alarm["delay"]; $delayTimestamp = $alarm["delayTimestamp"]; } if ($exists["alarm_on"] == 1) { return; } if (($exists === false || $exists["alarm_on"] == 0) && $delay > 0 && $delayTimestamp === null) { if (isset($alarm["multiCondition"]) && $alarm["multiCondition"] == 1) { $conditions = $alarm["conditions"]; $alarm["conditions"][0]["delayTimestamp"] = $timestamp; $this->updateDelayTimestampForMultiConditionalAlarm($conditions, $timestamp); } else { $alarmConditionId = $alarm["alarm_condition_id"]; $this->bulkAlarmDb->updateAlarmConditionDelayTimestamp($alarmConditionId, $timestamp); $alarm["delayTimestamp"] = $timestamp; } $delayTimestampPassed = false; } else { if ($delayTimestamp !== null && $delay > 0) { $timePassed = (strtotime($timestamp) - strtotime($delayTimestamp)) / 60; if ($timePassed < $delay) { $delayTimestampPassed = false; } } } if ($exists === false && $delayTimestampPassed === true) { $logStringTitle = $alarm["groupId"] > 0 ? "Bulk Alarm" : "Custom Alarm"; if (isset($alarm["multiCondition"]) && $alarm["multiCondition"] == 1) { $logString = "Multi Condition Alarm: " . $alarm["name"]; } else { $logString = $logStringTitle . " :" . $alarm["station_name"] . ": Variable (" . $alarm["variable_id"] . ")"; } $this->bulkAlarmDb->saveNewActiveAlarm($alarm, $value, $timestamp); $this->logger->logAction("215", $alarm["station_id"], 0, $logString); $this->logger->saveToAlarmLog($alarm, $value, 10, $timestamp); $alarmSender = $this->bulkAlarmDb->getActiveAlarmByIdAndOnOffString($alarmId); if ($alarm["multiCondition"] == 1) { $alarmSender["message"] = $alarm["message"]; } $this->sendAlarmMessage($alarmSender, $alarmSender["alarm_on"], 0); $this->bulkAlarmDb->updateLastRepeatTimestamp($alarmSender["active_alarm_id"]); $this->updateDelayTimestamp($alarm, null); } else { if ($exists["alarm_on"] == 0 && $delayTimestampPassed === true) { $this->bulkAlarmDb->updateActiveAlarm($exists["active_alarm_id"], $value, 1, $timestamp); $this->logger->saveToAlarmLog($alarm, $value, 10, $timestamp); $alarmSender = $this->bulkAlarmDb->getActiveAlarmByIdAndOnOffString($alarmId); if ($alarm["multiCondition"] == 1) { $alarmSender["message"] = $alarm["message"]; } $this->sendAlarmMessage($alarmSender, $alarmSender["alarm_on"], 0); $this->bulkAlarmDb->updateLastRepeatTimestamp($alarmSender["active_alarm_id"]); $this->updateDelayTimestamp($alarm, null); } } } public function updateDelayTimestampForMultiConditionalAlarm(&$conditions, $timestamp) { foreach ($conditions as &$condition) { $alarmConditionId = $condition["alarm_condition_id"]; $this->bulkAlarmDb->updateAlarmConditionDelayTimestamp($alarmConditionId, $timestamp); $condition["delayTimestamp"] = $timestamp; } } public function disableAlarm(array &$alarm, $value, $timestamp) { if ($value === "NaN") { return; } $alarmId = $alarm["alarm_id"]; $exists = $this->bulkAlarmDb->getActiveAlarm($alarmId); if ($exists !== false) { $wasActive = (int) $exists["alarm_on"]; if ($wasActive === 1) { $this->bulkAlarmDb->updateActiveAlarm($exists["active_alarm_id"], $value, 0, $exists["alarm_timestamp"]); $this->logger->saveToAlarmLog($alarm, $value, 9, $timestamp); if ($alarm["skip_off_alarm"] == 0) { $alarmSender = $this->bulkAlarmDb->getActiveAlarmByIdAndOnOffString($alarmId); $alarmSender["alarm_timestamp"] = $timestamp; if ($alarm["multiCondition"] == 1) { $alarmSender["message"] = $alarm["message"]; } $this->sendAlarmMessage($alarmSender, $alarmSender["alarm_on"], 0); $this->bulkAlarmDb->updateLastRepeatTimestamp($alarmSender["active_alarm_id"]); } } else { $this->updateDelayTimestamp($alarm, null); } if ((int) $exists["confirmed"] === 1) { $this->bulkAlarmDb->deleteCustomAlarmActive($alarmId); } } else { $this->updateDelayTimestamp($alarm, null); } } public function updateDelayTimestamp(&$alarm, $timestamp) { if (isset($alarm["multiCondition"]) && $alarm["multiCondition"] == 1) { if ($alarm["conditions"][0]["delayTimestamp"] !== null) { $this->updateDelayTimestampForMultiConditionalAlarm($alarm["conditions"], $timestamp); $alarm["conditions"][0]["delayTimestamp"] = $timestamp; } } else { if ($alarm["delayTimestamp"] !== null) { $alarm["delayTimestamp"] = $timestamp; $this->bulkAlarmDb->updateAlarmConditionDelayTimestamp($alarm["alarm_condition_id"], $timestamp); } } } public function sendAlarmMessage($alarm, $alarmStatus, $option) { $contactGroup = $alarm["contact_group_id"]; $subject = $this->swapPlaceholdersForValues($alarm, $alarm["subject"]); $headerFooter = $this->bulkAlarmDb->getAlarmMessageHeaderAndFooter(); $body = $headerFooter["warning_email_header"] . "<p>"; $body .= $this->swapPlaceholdersForValues($alarm, $alarm["message"]); $body .= "<p>" . $headerFooter["warning_email_footer"] . "<p>"; $this->mailDb->send(["emails" => [], "contact_group_id" => $contactGroup, "subject" => $subject, "body" => $body, "attachments" => []]); SendCommand::trigger($alarm["alarm_command_id"], $alarm["alarm_id"], $alarmStatus, "custom"); } private function getPlaceholderVariables() { return array("name" => "$ALARM_NAME$", "station_name" => "$SITE_NAME$", "NOW" => "$NOW$", "onOff" => "$ON/OFF$", "alarm_timestamp" => "$TIMESTAMP$", "alarm_value" => "$VALUE$", "limit_value" => "$LIMIT_VALUE$", "english_name" => "$VARIABLE_NAME$", "typeName" => "$ALARM_TYPE_NAME$"); } public function swapPlaceholdersForValues($alarm, $message) { global $localization; $phpDateTimeFormat = "Y-m-d H:i:s"; $placeholderVariables = $this->getPlaceholderVariables(); $now = new DateTime("now"); foreach ($placeholderVariables as $key => $placeholder) { if ($key == "onOff") { $onOffString = $alarm["alarm_on"] == 1 ? $alarm["warning_on_string"] : $alarm["warning_off_string"]; $message = str_replace($placeholder, $onOffString, $message); continue; } if ($key == "limit_value" && $alarm["compare_type"] == 1) { $secondCondition = $this->getValueForCompareVariable($alarm, $alarm["alarm_timestamp"]); $message = str_replace($placeholder, $secondCondition, $message); continue; } if ($key == "NOW") { $message = str_replace($placeholder, $now->format($phpDateTimeFormat), $message); } else { if (isset($alarm[$key])) { $message = str_replace($placeholder, $alarm[$key], $message); } } } return $message; } }
© 2023 Quttera Ltd. All rights reserved.