Ejemplo n.º 1
0
 public function testGetMessageWithTime_TwoSameCalls()
 {
     $log = new ListenerLog();
     StubFactory::clear();
     StubFactory::stubFunction('ListenerLog->find', array('return' => $log));
     $message1 = ListenerLog::getMessageWithTime(1, '12345', '423');
     $message2 = ListenerLog::getMessageWithTime(1, '12345', '423');
     $this->assertSame($log, $message1);
     $this->assertSame($log, $message2);
     $this->assertEquals(1, StubFactory::getStubCallCount('ListenerLog->find'));
 }
Ejemplo n.º 2
0
 protected function pollDataFromStation($station)
 {
     $this->_logger->log(__METHOD__, array('station' => $station->station_id_code));
     $matches = array();
     $source = $station->communication_esp_ip . ':' . $station->communication_esp_port;
     // Check IP_ADDRESS|DOMAIN_NAME:PORT pattern
     if (preg_match('/^([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]+)\\:([0-9]{1,5})$/', $source, $matches)) {
         $this->_logger->log(__METHOD__ . ': Matched.');
         $message = $this->pollData($matches[1], $matches[2], $this->generatePollCommand($station));
         if ($message != false) {
             ListenerLog::addNew($message, null, false, 'poller', $station->station_id);
         }
     }
 }
Ejemplo n.º 3
0
 protected function getData()
 {
     $this->_logger->log(__METHOD__ . ' $this->start_time: ' . print_r($this->start_time, 1));
     $this->_logger->log(__METHOD__ . ' $this->end_time: ' . print_r($this->end_time, 1));
     $result = ListenerLog::model()->getAllDataInType($this->station_type, $this->start_time, $this->end_time);
     $this->_logger->log(__METHOD__ . ' $result COUNT: ' . print_r(COUNT($result), 1));
     if (!is_null($result)) {
         //            $this->schedule_type_report->updateLastReportedMessageData($result[0]->created);
         $this->data = $result;
         return true;
     } else {
         $this->data = array();
         //            $this->schedule_type_report->updateLastReportedMessageData($this->end_time);
         return false;
     }
 }
Ejemplo n.º 4
0
 function actionIndex()
 {
     ini_set('memory_limit', '-1');
     print 'Checking `listener_log` table upgrade....<br/>';
     $sql = "SHOW COLUMNS FROM `" . ListenerLog::model()->tableName() . "` LIKE 'is_last'";
     $res = Yii::app()->db->createCommand($sql)->queryAll();
     if (!$res) {
         print '<br/><br/>Checked - requires update.<br/><br/>Attention! Script going to make small update to your database.... Please, be patient, don\'t use system before script is completed.';
         $sql = "ALTER TABLE `" . ListenerLog::model()->tableName() . "` ADD `is_last` tinyint(1) NOT NULL DEFAULT '0' AFTER `is_processed`";
         Yii::app()->db->createCommand($sql)->query();
         $sql = "SELECT * FROM `" . Station::model()->tableName() . "`";
         $stations = Yii::app()->db->createCommand($sql)->queryAll();
         if ($stations) {
             foreach ($stations as $key => $value) {
                 ListenerLog::updateIsLastForStation($value['station_id']);
             }
         }
         print '<br><br>.....<br><br>Done!. <br/><br/>You can continue work with <a href="' . It::baseUrl() . '">Delairco</a>';
     } else {
         print '<br/>Checked - doesn\'t require update. <br/><br/>You can continue work with <a href="' . It::baseUrl() . '">Delairco</a>';
     }
 }
 public static function getHistory($schedule_id, $page_size = 15)
 {
     if ($page_size) {
         $sql = "SELECT COUNT(t1.schedule_processed_id)\n                    FROM `" . ScheduleReportProcessed::model()->tableName() . "` t1\n                    WHERE `t1`.`schedule_id` = '" . $schedule_id . "'";
         $total = Yii::app()->db->createCommand($sql)->queryScalar();
     }
     if ($total || !$page_size) {
         if ($page_size) {
             $pages = new CPagination($total);
             $pages->pageSize = $page_size;
         }
         $sql = "SELECT \n\t\t\t\t\t\tt1.*, t2.message, t2.measuring_timestamp, t3.report_type \n                    FROM \n\t\t\t\t\t\t`" . ScheduleReportProcessed::model()->tableName() . "` t1\n                    LEFT JOIN \n\t\t\t\t\t\t`" . ListenerLog::model()->tableName() . "` t2 ON t2.log_id = t1.listener_log_id\n                    LEFT JOIN \n\t\t\t\t\t\t`" . ScheduleReport::model()->tableName() . "` t3 ON t3.schedule_id = t1.schedule_id\n                    WHERE \n\t\t\t\t\t\t`t1`.`schedule_id` = '" . $schedule_id . "'\n                    ORDER BY \n\t\t\t\t\t\t`t1`.`created` DESC";
         if ($page_size) {
             $sql .= " LIMIT " . $pages->currentPage * $pages->pageSize . ", " . $pages->pageSize;
         }
         $res = Yii::app()->db->createCommand($sql)->queryAll();
         if ($res) {
             $files_path = dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR . "files" . DIRECTORY_SEPARATOR . "schedule_reports";
             foreach ($res as $key => $value) {
                 if ($value['serialized_report_errors']) {
                     $res[$key]['report_errors'] = unserialize($value['serialized_report_errors']);
                 }
                 if ($value['serialized_report_explanations']) {
                     $res[$key]['report_explanations'] = unserialize($value['serialized_report_explanations']);
                 }
                 if (in_array($value['report_type'], array('synop', 'metar', 'speci')) && file_exists($files_path . DIRECTORY_SEPARATOR . $value['schedule_processed_id'])) {
                     $res[$key]['report_string_initial'] = file_get_contents($files_path . DIRECTORY_SEPARATOR . $value['schedule_processed_id']);
                 }
                 if ($value['listener_log_ids']) {
                     $sql = "SELECT t2.log_id, t2.message, t2.measuring_timestamp \n                                FROM  `" . ListenerLog::model()->tableName() . "` t2\n                                WHERE t2.log_id IN (" . $value['listener_log_ids'] . ")\n                                ORDER BY `t2`.`measuring_timestamp` DESC";
                     $res[$key]['logs'] = Yii::app()->db->createCommand($sql)->queryAll();
                 }
             }
         }
     }
     return array('list' => $res, 'pages' => $pages);
 }
Ejemplo n.º 6
0
 public function getCalculatedValue($station_id, $last_logs)
 {
     $last_logs_ids = array();
     if (is_array($last_logs)) {
         foreach ($last_logs as $value) {
             if (count($value) > 0) {
                 $last_logs_ids[] = $value->log_id;
             }
         }
     }
     $last_logs_ids[] = 0;
     $sql = "SELECT t1.listener_log_id, t1.value\n                FROM `" . StationCalculationData::model()->tableName() . "` `t1`\n                LEFT JOIN `" . StationCalculation::model()->tableName() . "` t2 ON t2.calculation_id = t1.calculation_id\n                LEFT JOIN `" . CalculationDBHandler::model()->tableName() . "` t3 ON t3.handler_id = t2.handler_id\n                LEFT JOIN `" . ListenerLog::model()->tableName() . "` t4 ON t4.log_id = t1.listener_log_id\n                WHERE `t3`.handler_id_code = ? AND t2.station_id = ? AND t1.listener_log_id IN (" . implode(',', $last_logs_ids) . ")\n                ORDER BY t4.measuring_timestamp DESC\n                LIMIT 2 ";
     $res = Yii::app()->db->createCommand($sql)->queryAll(true, array($this->handler_id_code, $station_id));
     $return = array('last' => '-', 'change' => 'no', 'metric_html_code' => $this->metric_html_code, 'display_name' => $this->display_name);
     if (!$res) {
         return $return;
     }
     if ($res[0]['listener_log_id'] && $res[0]['listener_log_id'] == $last_logs_ids[0]) {
         $return['last'] = number_format(round($res[0]['value'], 1), 1);
         if ($res[1]['listener_log_id']) {
             if ($res[0]['value'] > $res[1]['value']) {
                 $return['change'] = 'up';
             } else {
                 if ($res[0]['value'] < $res[1]['value']) {
                     $return['change'] = 'down';
                 }
             }
         }
     }
     return $return;
 }
 public function prepareSection4()
 {
     $this->_logger->log(__METHOD__);
     $s = 4;
     $i = 0;
     $measuring_timestamp = strtotime($this->listener_log_info->measuring_timestamp);
     //        $measuring_year      = date('Y', $measuring_timestamp);
     //        $measuring_month     = date('m', $measuring_timestamp);
     //        $measuring_day       = date('d', $measuring_timestamp);
     //        $measuring_hour      = date('H', $measuring_timestamp);
     //        $measuring_minute    = date('i', $measuring_timestamp);
     //        $measuring_second    = date('s', $measuring_timestamp);
     $script_runtime = strtotime($this->schedule_process_info->check_period_end);
     $script_runtime_year = date('Y', $script_runtime);
     $script_runtime_month = date('m', $script_runtime);
     $script_runtime_day = date('d', $script_runtime);
     $script_runtime_hour = date('H', $script_runtime);
     $script_runtime_minute = date('i', $script_runtime);
     $script_runtime_second = date('s', $script_runtime);
     $sensors_3hr_ago = array();
     $sensors_24hr_ago = array();
     $x_hr_ago_1 = date('Y-m-d H:i:s', mktime($script_runtime_hour - 3, $script_runtime_minute, $script_runtime_second, $script_runtime_month, $script_runtime_day, $script_runtime_year));
     $x_hr_ago_2 = date('Y-m-d H:i:s', mktime($script_runtime_hour - 4, $script_runtime_minute, $script_runtime_second, $script_runtime_month, $script_runtime_day, $script_runtime_year));
     $log_3_hr_ago = ListenerLog::getMessageWithTime($this->station_info->station_id, $x_hr_ago_1, $x_hr_ago_2);
     if (!is_null($log_3_hr_ago)) {
         $sensors_3hr_ago = $this->prepareSensorsInfo($log_3_hr_ago->log_id);
     }
     $x_hr_ago_1 = date('Y-m-d H:i:s', mktime($script_runtime_hour, $script_runtime_minute, $script_runtime_second, $script_runtime_month, $script_runtime_day - 1, $script_runtime_year));
     $x_hr_ago_2 = date('Y-m-d H:i:s', mktime($script_runtime_hour - 1, $script_runtime_minute, $script_runtime_second, $script_runtime_month, $script_runtime_day - 1, $script_runtime_year));
     $log_24_hr_ago = ListenerLog::getMessageWithTime($this->station_info->station_id, $x_hr_ago_1, $x_hr_ago_2);
     if (!is_null($log_24_hr_ago)) {
         $sensors_24hr_ago = $this->prepareSensorsInfo($log_24_hr_ago->log_id);
     }
     /// ??? RECALCULATE !!!!
     $this->report_parts[$s][$i] = $this->prepare_binary_value(0, 24);
     $this->explanations[$s][$i][] = 'Octets 1-3: <span>' . $this->report_parts[$s][$i] . '</span> => <span></span> (length of section4 in octets)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value(0, 8);
     $this->explanations[$s][$i][] = 'Octets 4: <span>' . $this->report_parts[$s][$i] . '</span> reserved';
     $i++;
     //3 01 090: Fixed surface station identification, time, horizontal and vertical coordinates
     $this->report_parts[$s][$i] = $this->prepare_binary_value($this->station_info->wmo_block_number, 7);
     $this->explanations[$s][$i][] = '301090 -> 301004 -> 001001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $this->station_info->wmo_block_number . '</span> (WMO Block #, 7 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($this->station_info->station_number, 10);
     $this->explanations[$s][$i][] = '301090 -> 301004 -> 001002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $this->station_info->station_number . '</span> (station number, 10 bits)';
     $i++;
     $station_display_name = substr($this->station_info->display_name, 0, 20);
     $tmp_str = '';
     $tmp_str_2 = '';
     for ($j = 0; $j < strlen($station_display_name); $j++) {
         $tmp = $this->prepare_binary_value(ord($station_display_name[$j]), 8);
         $tmp_str .= $tmp;
         $tmp_str_2 .= ' ' . $tmp;
     }
     $this->report_parts[$s][$i] = str_pad($tmp_str, 160, '0', STR_PAD_RIGHT);
     $this->explanations[$s][$i][] = '301090 -> 301004 -> 001015: <span>' . str_pad($tmp_str_2, 160 + strlen($station_display_name), '0', STR_PAD_RIGHT) . '</span> => <span>' . $station_display_name . '</span> (station code, 160 bits. Each letter incoded into 7bits binary with and padded with left 0 to 8bits. Then joined string is right-padded with 0 to fit 160bits length)';
     $i++;
     $this->report_parts[$s][$i] = '00';
     $this->explanations[$s][$i][] = '301090 -> 301004 -> 002001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>0</span> (Type of station, 2 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($script_runtime_year, 12);
     $this->explanations[$s][$i][] = '301090 -> 301011 -> 00 4001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $script_runtime_year . '</span> (Year, 12 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($script_runtime_month, 4);
     $this->explanations[$s][$i][] = '301090 -> 301011 -> 004002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $script_runtime_month . '</span> (Month, 4 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($script_runtime_day, 6);
     $this->explanations[$s][$i][] = '301090 -> 301011 -> 004003: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $script_runtime_day . '</span> (Day, 6 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($script_runtime_hour, 5);
     $this->explanations[$s][$i][] = '301090 -> 301012 -> 004004: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $script_runtime_hour . '</span> (Hour, 5 bits)';
     $i++;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($script_runtime_minute, 6);
     $this->explanations[$s][$i][] = '301090 -> 301012 -> 004005: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $script_runtime_minute . '</span> (Minute, 6 bits)';
     $i++;
     // 301090 -> 301021 -> 005001 => Latitude
     // 25 bits. Metric = degree. Scale = 5. Reference = –9000000
     $tmp = round($this->station_info->lat, 5) * 100000 + 9000000;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 25);
     $this->explanations[$s][$i][] = '301090 -> 301021 -> 005001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>round(' . $this->station_info->lat . ', 5) * 10^5 -(-9000000) = ' . $tmp . '</span> (Latitude, 25 bits)';
     $i++;
     // 301090 -> 301021 -> 006001 => Longitude.
     // 26 bits. Metric = degree.  Scale = 5.  Ref value = -18000000
     $tmp = round($this->station_info->lng, 5) * 100000 + 18000000;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 26);
     $this->explanations[$s][$i][] = '301090 -> 301021 -> 006001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>round(' . $this->station_info->lng . ', 5) * 10^5 -(-18000000) = ' . $tmp . '</span> (Longitude, 26 bits)';
     $i++;
     // 301090 -> 007030 => Altitude, Height of station ground above mean sea level.
     // 17 bits. Metric = m, Scale = 1, Ref = 4000
     $tmp = round($this->station_info->altitude, 1) * 10 + 4000;
     $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 17);
     $this->explanations[$s][$i][] = '301090 -> 007030: <span>' . $this->report_parts[$s][$i] . '</span> => <span>round(' . $this->station_info->altitude . ', 1) * 10^1 -(-4000) = ' . $tmp . '</span> (Altitude, 17 bits)';
     $i++;
     // 301090 -> 007031: Barometer Height.
     // 17 bits. Metric = m, Scale = 1, Ref = 4000
     $expl_val = '';
     if (isset($this->sensors['pressure'])) {
         $tmp = It::convertMetric($this->sensors['pressure_height']['height'], $this->sensors['pressure_height']['height_metric_code'], 'meter');
         $str_tmp = round($tmp + $this->station_info->altitude, 1) * 10 + 4000;
         $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 17);
         $expl_val = $this->sensors['pressure_height']['height'] . ' ' . $this->sensors['pressure_height']['height_metric_code'];
         if ($this->sensors['pressure_height']['height_metric_code'] != 'meter') {
             $expl_val .= ' = ' . $tmp . ' meter';
         }
         $expl_val .= ' ~ round( (' . $tmp . ' + ' . $this->station_info->altitude . '), 1)*10^1 -(-4000) = ' . $str_tmp;
     } else {
         $this->report_parts[$s][$i] = '11111111111111111';
         $expl_val = 'No Pressure sensor';
     }
     $this->explanations[$s][$i][] = '301090 -> 007031: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Barometer Height, m, 17 bits)';
     $i++;
     // 3 02 031: Pressure.
     // 302031 -> 302001 -> 010004: Pressure data
     // Metric = Pa. Scale = –1. Reference value = 0. Size = 14 bits
     if (isset($this->sensors['pressure'])) {
         if ($this->sensors['pressure']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111111';
             $expl_val = 'Data from Pressure sensor is unavailable';
         } else {
             $tmp = It::convertMetric($this->sensors['pressure']['sensor_feature_value'], $this->sensors['pressure']['metric_code'], 'pascal');
             $str_tmp = round($tmp / 10, 0);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 14);
             $expl_val = $this->sensors['pressure']['sensor_feature_value'] . ' ' . $this->sensors['pressure']['metric_code'];
             if ($this->sensors['pressure']['metric_code'] != 'pascal') {
                 $expl_val .= ' = ' . $tmp . ' pascal';
             }
             $expl_val .= ' ~ round(' . $tmp . ' * 10^(-1), 0) - 0 = ' . $str_tmp;
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111';
         $expl_val = 'No Pressure sensor';
     }
     $this->explanations[$s][$i][] = '302031 -> 302001 -> 010004: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span>  (Barometer Pressure, Pa, 14 bits)';
     $i++;
     // 302031 -> 302001 -> 010051: Pressure reduced to mean sea level
     // 14 bits. Metric = Pa. Scale = –1. Ref =  0.
     if (isset($this->calculations['PressureSeaLevel'])) {
         $tmp = It::convertMetric($this->calculations['PressureSeaLevel']['value'], 'hpascal', 'pascal');
         $str_tmp = round($tmp / 10, 0);
         $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 14);
         $expl_val = $this->calculations['PressureSeaLevel']['value'] . ' hPa = ' . $tmp . ' Pa ~ round(' . $tmp . ' * 10^(-1), 0) - 0 = ' . $str_tmp . '</span>';
     } else {
         $this->report_parts[$s][$i] = '11111111111111';
         $expl_val = 'No Pressure MSL Calculation';
     }
     $this->explanations[$s][$i][] = '302031 -> 302001 -> 010051: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Pressure MSL, Pa, 14bits)';
     $i++;
     // 302031 -> 302001 -> 010061: 3-hour pressure change
     // 10 bits. Metric = Pa. Scale = -1. Ref = -500
     // AND
     // 302031 -> 302001 -> 010063: Characteristic of pressure tendency
     // 4 bits. Code table value. Scale = 0. Ref = 0
     if (isset($this->sensors['pressure']) && isset($sensors_3hr_ago['pressure'])) {
         if ($this->sensors['pressure']['is_m']) {
             $this->report_parts[$s][$i] = '1111111111';
             $this->explanations[$s][$i][] = '302031 -> 302001 -> 010061: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Last data from Pressure sensor is unavailable</span> (3h Pressure change, 10 bits)';
             $i++;
             $this->report_parts[$s][$i] = '1111';
             $this->explanations[$s][$i][] = '302031 -> 302001 -> 010063: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Last data from Pressure sensor is unavailable</span> (3h Pressure change Tendency, 4bits)';
         } else {
             if ($sensors_3hr_ago['pressure']['is_m']) {
                 $this->report_parts[$s][$i] = '1111111111';
                 $this->explanations[$s][$i][] = '302031 -> 302001 -> 010061: <span>' . $this->report_parts[$s][$i] . '</span> => <span>3h ago data from Pressure sensor is unavailable</span> (3h Pressure change, 10 bits)';
                 $i++;
                 $this->report_parts[$s][$i] = '1111';
                 $this->explanations[$s][$i][] = '302031 -> 302001 -> 010063: <span>' . $this->report_parts[$s][$i] . '</span> => <span>3h ago data from Pressure sensor is unavailable</span> (3h Pressure change Tendency, 4bits)';
             } else {
                 $pressure_3hr = $sensors_3hr_ago['pressure']['sensor_feature_value'];
                 $pressure_3hr_metric = $sensors_3hr_ago['pressure']['metric_code'];
                 $pressure_3hr = It::convertMetric($pressure_3hr, $pressure_3hr_metric, 'pascal');
                 $pressure_now = $this->sensors['pressure']['sensor_feature_value'];
                 $pressure_now_metric = $this->sensors['pressure']['metric_code'];
                 $pressure_now = It::convertMetric($pressure_now, $pressure_now_metric, 'pascal');
                 $tmp3 = round(($pressure_now - $pressure_3hr) / 10, 0);
                 $str_tmp = abs($tmp3) + 500;
                 $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 10);
                 $expl_val = '302031 -> 302001 -> 010061: <span>' . $this->report_parts[$s][$i] . '</span> => ';
                 $expl_val .= '<span>~ round(' . $pressure_now . ' - ' . $pressure_3hr . ') * 10^(-1), 0) Pa = ' . $tmp3 . ' Pa ~  |' . $tmp3 . '| -(-500) = ' . $str_tmp . ' </span> (3h Pressure change, Pa, 10bits)';
                 $this->explanations[$s][$i][] = $expl_val;
                 $i++;
                 if ($pressure_now > $pressure_3hr) {
                     $this->report_parts[$s][$i] = '0010';
                     $expl_val = '<span>2 = Increased</span>';
                 } else {
                     if ($pressure_now < $pressure_3hr) {
                         $this->report_parts[$s][$i] = '0111';
                         $expl_val = '<span>7 = Decreased</span>';
                     } else {
                         $this->report_parts[$s][$i] = '0000';
                         $expl_val = '<span>4 = Stable</span>';
                     }
                 }
                 $this->explanations[$s][$i][] = '302031 -> 302001 -> 010063: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (3h Pressure change Tendency, 4bits)';
             }
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111';
         $this->explanations[$s][$i][] = '302031 -> 302001 -> 010061: <span>' . $this->report_parts[$s][$i] . '</span> => <span>No pressure sensor</span> (3h Pressure change, 10 bits)';
         $i++;
         $this->report_parts[$s][$i] = '1111';
         $this->explanations[$s][$i][] = '302031 -> 302001 -> 010063: <span>' . $this->report_parts[$s][$i] . '</span> => <span>No pressure sensor</span> (3h Pressure change Tendency, 4bits)';
     }
     $i++;
     // 302031 -> 010062: 24-hour pressure change
     // 11 bits. Metric = Pa. Scale = -1. Ref = -1000
     if (isset($this->sensors['pressure']) && isset($sensors_24hr_ago['pressure'])) {
         if ($this->sensors['pressure']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111';
             $expl_val = '<span>Last data from Pressure sensor is unavailable</span>';
         } else {
             if ($sensors_24hr_ago['pressure']['is_m']) {
                 $this->report_parts[$s][$i] = '11111111111';
                 $expl_val = '<span>24h ago data from Pressure sensor is unavailable</span>';
             } else {
                 $pressure_24hr = It::convertMetric($sensors_24hr_ago['pressure']['sensor_feature_value'], $sensors_24hr_ago['pressure']['metric_code'], 'pascal');
                 $pressure_now = It::convertMetric($this->sensors['pressure']['sensor_feature_value'], $this->sensors['pressure']['metric_code'], 'pascal');
                 $tmp3 = round(($pressure_now - $pressure_24hr) / 10, 0);
                 $str_tmp = abs($tmp3) + 1000;
                 $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 11);
                 $expl_val = '<span>~ round((' . $pressure_now . ' - ' . $pressure_24hr . ') * 10^(-1), 0) Pa = ' . $tmp3 . ' Pa ~ |' . $tmp3 . '| -(-1000) = ' . $str_tmp . '</span>';
             }
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $expl_val = '<span>No pressure sensor</span>';
     }
     $this->explanations[$s][$i][] = '302031 -> 010062: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (24h Pressure change, Pa, 11bits)';
     $i++;
     // 302031 -> 007004: Pressure
     // 14 bits. Metric = Pa. Scale = -1. Ref = 0
     $this->report_parts[$s][$i] = '11111111111111';
     $this->explanations[$s][$i][] = '302031 -> 007004: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Pressure, Pa, 14bits)';
     $i++;
     //302031 -> 010009: Geopotential height
     // 17 bits. Metric = gpm. Scale = 0. Ref = -1000.
     $this->report_parts[$s][$i] = '11111111111111111';
     $this->explanations[$s][$i][] = '302031 -> 010009: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (GEOPOTENTIAL HEIGHT, GPM, 17bits)';
     $i++;
     //3 02 035: Basic synoptic “instantaneous” data
     //3 02 035 -> 3 02 032: Temperature and Humidity data.
     //
     // 302035 -> 302032 -> 012101: Height of temperature sensor above local ground
     // Metric = m. Scale = 2. Ref = 0. 16 bits
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302035 -> 302032 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of temperature/humidity sensors, 16bits)';
     $i++;
     // 302035 -> 302032 -> 012101: Temperature/dry-bulb temperature
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     if (isset($this->sensors['temperature'])) {
         if ($this->sensors['temperature']['is_m']) {
             $this->report_parts[$s][$i] = '1111111111111111';
             $expl_val = '<span>Last data from Temperature sensor is unavailable</span>';
         } else {
             $tmp = It::convertMetric($this->sensors['temperature']['sensor_feature_value'], $this->sensors['temperature']['metric_code'], 'kelvin');
             $str_tmp = round($tmp * 100);
             $this->report_parts[$s][$i] = ($tmp > 0 ? '0' : '1') . $this->prepare_binary_value(abs($str_tmp), 15);
             $expl_val = '<span>' . $this->sensors['temperature']['sensor_feature_value'] . ' ' . $this->sensors['temperature']['metric_code'];
             if ($this->sensors['temperature']['metric_code'] != 'kelvin') {
                 $expl_val .= ' = ' . $tmp . ' kelvin';
             }
             $expl_val .= ' ~ |round(' . $tmp . ' * 10^2 - 0)| = ' . round($tmp * 100) . ' (+left bit = ' . ($tmp > 0 ? '0' : '1') . ' because ' . ($tmp > 0 ? 'positive' : 'negative') . ') ';
             $expl_val .= '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111111111';
         $expl_val = '<span>No temperature sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302032 -> 012101: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Temperature, kelvin degree, 16bits)';
     $i++;
     // 302035 -> 302032 -> 012103: Dew-point temperature
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     if (isset($this->calculations['DewPoint'])) {
         $tmp = It::convertMetric($this->calculations['DewPoint']['value'], 'celsius', 'kelvin');
         $str_tmp = round($tmp * 100);
         $this->report_parts[$s][$i] = ($tmp > 0 ? '0' : '1') . $this->prepare_binary_value(abs($str_tmp), 15);
         $expl_val = '<span>' . $this->calculations['DewPoint']['value'] . ' celsius';
         $expl_val .= ' = ' . $tmp . ' kelvin';
         $expl_val .= ' ~ |round(' . $tmp . ' * 10^2 - 0)| = ' . $str_tmp . ' (+left bit = ' . ($tmp > 0 ? '0' : '1') . ' because ' . ($tmp > 0 ? 'positive' : 'negative') . ')';
         $expl_val .= '</span>';
     } else {
         $this->report_parts[$s][$i] = '1111111111111111';
         $expl_val = '<span>No calculation</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302032 -> 012103: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . '  (DewPoint, kelvin, 16bits)';
     $i++;
     // 302035 -> 302032 -> 013003: Relative humidity
     // 7 bits. Metric = %. Scale = 0. Ref = 0.
     if (isset($this->sensors['humidity'])) {
         if ($this->sensors['humidity']['is_m']) {
             $this->report_parts[$s][$i] = '1111111';
             $expl_val = '<span>Last data from Humidity sensor is unavailable</span>';
         } else {
             $str_tmp = round($this->sensors['humidity']['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 7);
             $expl_val = '<span>round(' . $this->sensors['humidity']['sensor_feature_value'] . ')</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111';
         $expl_val = '<span>No humidity sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302032 -> 013003:<span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . '   (RELATIVE HUMIDITY, %, 7bits)';
     $i++;
     // 302035 -> 302033 -> 007032:  Height of visibility sensor above local ground
     // 16 bits. Metric = m. Scale = 2. Ref = 0
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302035 -> 302033 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Hight of visibility sensor, 16bits)';
     $i++;
     // 302035 -> 302033 -> 020001: Horizontal Visibility
     // 13 bits. Metric = m. Scale = -1. Ref = 0
     if (isset($this->sensors['visibility_1'])) {
         if ($this->sensors['visibility_1']['is_m']) {
             $this->report_parts[$s][$i] = '1111111111111';
             $expl_val = '<span>Last data from Visibility sensor is unavailable</span>';
         } else {
             $tmp = It::convertMetric($this->sensors['visibility_1']['sensor_feature_value'], $this->sensors['visibility_1']['metric_code'], 'meter');
             $str_tmp = round($tmp / 10, 0);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 13);
             $expl_val = '<span>' . $this->sensors['visibility_1']['sensor_feature_value'] . ' ' . $this->sensors['visibility_1']['metric_code'] . ' = ' . $tmp . ' meter. Apply scale=-1 => ' . $str_tmp . ' </span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111111';
         $expl_val = '<span>No Visibility sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302033 -> 020001: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Horizontal Visibility, 13bits)';
     $i++;
     // 302035 -> 302034 -> 007032: Height of Rain sensor
     // 16 bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302035 -> 302034 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of Rain sensor, 16bits)';
     $i++;
     // 302035 -> 302034 -> 013023: Total precipitation past 24 hours, kg/m2
     // 14 bits. Metric = kg/m2. Scale = 1. Ref = -1.
     if (isset($this->sensors['rain_in_period'])) {
         if ($this->sensors['rain_in_period']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111111';
             $expl_val = '<span>Last data from Rain sensor is unavailable</span>';
         } else {
             $handler_obj = SensorHandler::create($this->sensors['rain_in_period']['handler_id_code']);
             $rain_last_24_hr = $handler_obj->getTotalInLastXHr($this->sensors['rain_in_period']['sensor_feature_id'], $measuring_timestamp, 24, false)['total'];
             $tmp = It::convertMetric($rain_last_24_hr, $this->sensors['rain_in_period']['metric_code'], 'millimeter');
             $tmp_str = round($tmp, 1) * 10 - -1;
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp_str, 14);
             $expl_val = '<span>' . $rain_last_24_hr . ' ' . $this->sensors['rain_in_period']['metric_code'];
             if ($this->sensors['rain_in_period']['metric_code'] != 'millimeter') {
                 $expl_val .= ' = ' . $tmp . ' millimeter';
             }
             $expl_val .= ' ~ round(' . $tmp . ', 1) * 10^1 -(-1) = ' . $tmp_str . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111';
         $expl_val = '<span>No rain sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302034 -> 013023: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . '(Total precipitation past 24 hours, kg/m2, 14bits)';
     $i++;
     // 302035 -> 007032: Height of Rain sensor
     // 16bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302035 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of Rain sensor, 16bits)';
     $i++;
     // -- 3 02 035 -> 3 02 004: Cloud Data --
     // 302035 -> 302004 -> 020010: Cloud cover
     // 7 bits. Metric = %. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111111';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020010: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud cover, %, 7bits)';
     // 7bits
     $i++;
     // 302035 -> 302004 -> 008002: Vertical Significance
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = ' 302035 -> 302004 -> 008002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical Significance, 6 bits)';
     $i++;
     // 302035 -> 302004 -> 020011: Cloud Amount
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     //		if (isset($this->sensors['cloud_amount_amount_total']))
     //		{
     //            if ($this->sensors['cloud_amount_amount_total']['is_m'])
     //			{
     //                $this->report_parts[$s][$i] = '1111';
     //                $expl_val = 'Last data about Cloud Amount is unavailable';
     //            }
     //			else
     //			{
     //                $tmp1 = $this->_get_cloud_cover_code(round($this->sensors['cloud_amount_amount_total']['sensor_feature_value'], 1));
     //
     //				$this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 4);
     //                $expl_val = $tmp1 .' ('. round($this->sensors['cloud_amount_amount_total']['sensor_feature_value']) .'/8)';
     //            }
     //        }
     //		else
     //		{
     //            $this->report_parts[$s][$i] = '1111';
     //            $expl_val = 'No Cloud Amount sensor';
     //        }
     //        $this->explanations[$s][$i][] = '302035 -> 302004 -> 020011: <span>'.$this->report_parts[$s][$i].'</span> => <span>'. $expl_val .'</span> (Cloud Amount, 4bits)';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020011: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud Amount, 4bits)';
     $i++;
     // 302035 -> 302004 -> 020013: Height of base cloud
     // 11 bits. Metric = m. Scale = -1. Ref = -40.
     $this->report_parts[$s][$i] = '11111111111';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020013: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of base cloud, 11bits)';
     $i++;
     // 302035 -> 302004 -> 020012: Cloud Type of low clouds
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020012: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud Type of low clouds, 6bits)';
     $i++;
     // 302035 -> 302004 -> 020012: Cloud Type of middle clouds
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020012: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud Type of middle clouds, 6bits)';
     $i++;
     // 302035 -> 302004 -> 020012: Cloud Type of high clouds
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302004 -> 020012: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud Type of high clouds, 6bits)';
     $i++;
     // 307080 -> 302035 -> 031001: 3 repetitions for Cloud Layers.
     // 8 bits
     // number of repetitions should be there.
     // As far as we  have 3 layers of clouds – this value is fixed to 3.
     $this->report_parts[$s][$i] = $this->prepare_binary_value(3, 8);
     $this->explanations[$s][$i][] = '307080 -> 302035 -> 031001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>3</span> repetitions for 3 Cloud Layers.(Decide here how much repetition we need, 8bits)';
     $i++;
     // Repetition #1
     $cloudAmountSensor = isset($this->sensors['cloud_amount_amount_1']) ? $this->sensors['cloud_amount_amount_1'] : null;
     // 302035 -> 302005 -> 008002 (Repetition #1): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '111111';
             $expl_val = '<span>Missing</span>';
         } else {
             $tmp1 = $this->getVerticalSignificance(1, $cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 6);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '111111';
         $expl_val = '<span>Missing (No such measurement)</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 008002 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302035 -> 302005 -> 020011 (Repetition #1): Cloud amount
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '1111';
             $expl_val = '<span>Last data about Cloud Amount is unavailable</span>';
         } else {
             $tmp1 = $this->_get_cloud_cover_code($cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 4);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111';
         $expl_val = '<span>No Cloud Amount sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020011 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> =>  ' . $expl_val . ' (Cloud amount, 4bits)';
     $i++;
     // 302035 -> 302005 -> 020012 (Repetition #1): Cloud Type
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020012 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing (No such measurement)</span> (Cloud Type, 6bits)';
     $i++;
     $cloudHeightSensor = isset($this->sensors['cloud_amount_height_1']) ? $this->sensors['cloud_amount_height_1'] : (isset($this->sensors['cloud_height_height_1']) ? $this->sensors['cloud_height_height_1'] : null);
     // 302035 -> 302005 -> 020013 (Repetition #1): Height of Base Cloud
     // 11 bits. Metric = m. Scale = -1. Ref = -40.
     if (isset($cloudHeightSensor)) {
         if ($cloudHeightSensor['is_m']) {
             $this->report_parts[$s][$i] = '11111111111';
             $expl_val = '<span>Last data about Cloud Height is unavailable</span>';
         } else {
             $tmp1 = It::convertMetric($cloudHeightSensor['sensor_feature_value'], $cloudHeightSensor['metric_code'], 'meter');
             $tmp2 = round($tmp1 / 10 + 40);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp2, 11);
             $expl_val = '<span>' . round($cloudHeightSensor['sensor_feature_value']) . ' ' . $cloudHeightSensor['metric_code'] . ' = ' . round($tmp1, 1) . ' meter.</span> With scale=-1 and ref=40: <span>' . $tmp2 . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $expl_val = '<span>No Cloud Height sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020013 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Height of Base Cloud, 11bits)';
     $i++;
     // Repetition #2
     $cloudAmountSensor = isset($this->sensors['cloud_amount_amount_2']) ? $this->sensors['cloud_amount_amount_2'] : null;
     // 302035 -> 302005 -> 008002 (Repetition #2): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '111111';
             $expl_val = '<span>Missing</span>';
         } else {
             $tmp1 = $this->getVerticalSignificance(2, $cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 6);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '111111';
         $expl_val = '<span>Missing (No such measurement)</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 008002 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302035 -> 302005 -> 020011 (Repetition #2): Cloud amount
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '1111';
             $expl_val = '<span>Last data about Cloud Amount is unavailable</span>';
         } else {
             $tmp1 = $this->_get_cloud_cover_code($cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 4);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111';
         $expl_val = '<span>No Cloud Amount sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020011 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> =>  ' . $expl_val . ' (Cloud amount, 4bits)';
     $i++;
     // 302035 -> 302005 -> 020012 (Repetition #2): Cloud Type
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020012 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing (No such measurement)</span> (Cloud Type, 6bits)';
     $i++;
     $cloudHeightSensor = isset($this->sensors['cloud_amount_height_2']) ? $this->sensors['cloud_amount_height_2'] : (isset($this->sensors['cloud_height_height_2']) ? $this->sensors['cloud_height_height_2'] : null);
     // 302035 -> 302005 -> 020013 (Repetition #2): Height of Base Cloud
     // 11 bits. Metric = m. Scale = -1. Ref = -40.
     if (isset($cloudHeightSensor)) {
         if ($cloudHeightSensor['is_m']) {
             $this->report_parts[$s][$i] = '11111111111';
             $expl_val = '<span>Last data about Cloud Height is unavailable</span>';
         } else {
             $tmp1 = It::convertMetric($cloudHeightSensor['sensor_feature_value'], $cloudHeightSensor['metric_code'], 'meter');
             $tmp2 = round($tmp1 / 10 + 40);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp2, 11);
             $expl_val = '<span>' . round($cloudHeightSensor['sensor_feature_value']) . ' ' . $cloudHeightSensor['metric_code'] . ' = ' . round($tmp1, 1) . ' meter.</span> With scale=-1 and ref=40: <span>' . $tmp2 . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $expl_val = '<span>No Cloud Height sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020013 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Height of Base Cloud, 11bits)';
     $i++;
     // Repetition #3
     // if layer 3 is missing then check layer 4.
     $cloudAmountSensor = isset($this->sensors['cloud_amount_amount_3']) && $this->sensors['cloud_amount_amount_3']['is_m'] != 1 ? $this->sensors['cloud_amount_amount_3'] : (isset($this->sensors['cloud_amount_amount_4']) ? $this->sensors['cloud_amount_amount_4'] : null);
     $group = isset($this->sensors['cloud_amount_amount_3']) && $this->sensors['cloud_amount_amount_3']['is_m'] != 1 ? 3 : (isset($this->sensors['cloud_amount_amount_4']) ? 4 : null);
     // 302035 -> 302005 -> 008002 (Repetition #3): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '111111';
             $expl_val = '<span>Missing</span>';
         } else {
             $tmp1 = $this->getVerticalSignificance($group, $cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 6);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '111111';
         $expl_val = '<span>Missing (No such measurement)</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 008002 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302035 -> 302005 -> 020011 (Repetition #3): Cloud amount
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     if (isset($cloudAmountSensor)) {
         if ($cloudAmountSensor['is_m']) {
             $this->report_parts[$s][$i] = '1111';
             $expl_val = '<span>Last data about Cloud Amount is unavailable</span>';
         } else {
             $tmp1 = $this->_get_cloud_cover_code($cloudAmountSensor['sensor_feature_value']);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp1, 4);
             $expl_val = '<span>' . $tmp1 . ' (' . $cloudAmountSensor['sensor_feature_value'] . '/8)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '1111';
         $expl_val = '<span>No Cloud Amount sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020011 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> =>  ' . $expl_val . ' (Cloud amount, 4bits)';
     $i++;
     // 302035 -> 302005 -> 020012 (Repetition #3): Cloud Type
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020012 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing (No such measurement)</span> (Cloud Type, 6bits)';
     $i++;
     $cloudHeightSensor = isset($this->sensors['cloud_amount_height_3']) ? $this->sensors['cloud_amount_height_3'] : (isset($this->sensors['cloud_height_height_3']) ? $this->sensors['cloud_height_height_3'] : null);
     // 302035 -> 302005 -> 020013 (Repetition #3): Height of Base Cloud
     // 11 bits. Metric = m. Scale = -1. Ref = -40.
     if (isset($cloudHeightSensor)) {
         if ($cloudHeightSensor['is_m']) {
             $this->report_parts[$s][$i] = '11111111111';
             $expl_val = '<span>Last data about Cloud Height is unavailable</span>';
         } else {
             $tmp1 = It::convertMetric($cloudHeightSensor['sensor_feature_value'], $cloudHeightSensor['metric_code'], 'meter');
             $tmp2 = round($tmp1 / 10 + 40);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp2, 11);
             $expl_val = '<span>' . round($cloudHeightSensor['sensor_feature_value']) . ' ' . $cloudHeightSensor['metric_code'] . ' = ' . round($tmp1, 1) . ' meter.</span> With scale=-1 and ref=40: <span>' . $tmp2 . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $expl_val = '<span>No Cloud Height sensor</span>';
     }
     $this->explanations[$s][$i][] = '302035 -> 302005 -> 020013 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Height of Base Cloud, 11bits)';
     $i++;
     // 3 02 036: Clouds with bases below station level
     // 302036 -> 031001: 1 repetition
     // 8 bits
     // 1 repetition only, so 1 is fixed
     $this->report_parts[$s][$i] = $this->prepare_binary_value(1, 8);
     $this->explanations[$s][$i][] = '302036 -> 031001 (Decide here how much repetition we need): <span>' . $this->report_parts[$s][$i] . '</span> => <span>1</span>';
     $i++;
     // 302036 -> 008002 (Repetition #1): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302036 -> 008002 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302036 -> 020011 (Repetition #1): Cloud amount
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '302036 -> 020011 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud amount, 4bits)';
     $i++;
     // 302036 -> 020012 (Repetition #1): Cloud Type
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302036 -> 020012 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud Type, 6bits)';
     $i++;
     // 302036 -> 020014 (Repetition #1): Height of top of cloud
     // 11 bits. Metric = m. Scale = -1. Ref = -40;
     $this->report_parts[$s][$i] = '11111111111';
     $this->explanations[$s][$i][] = '302036 -> 020014 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of top of cloud, 11bits)';
     $i++;
     // 302036 -> 020017 (Repetition #1): Cloud top description
     // 4 bits. Metric = code table. Scale = 0. Ref = 0;
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '302036 -> 020017 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud top description, 4bits)';
     $i++;
     // 3 02 047: Direction of cloud drift
     // 302047 -> 008002 (Repetition #1): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302047 -> 008002 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302047 -> 020054 (Repetition #1): True direction
     // 9 bits. Metric = degree true. Scale = 0. Ref = 9
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302047 -> 020054 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (True direction from which clouds are moving, 9bits)';
     $i++;
     // 302047 -> 008002 (Repetition #2): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302047 -> 008002 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302047 -> 020054 (Repetition #2): True direction
     // 9 bits. Metric = degree true. Scale = 0. Ref = 9
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302047 -> 020054 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (True direction from which clouds are moving, 9bits)';
     $i++;
     // 302047 -> 008002 (Repetition #3): Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302047 -> 008002 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical significance (surface observations), 6bits)';
     $i++;
     // 302047 -> 020054 (Repetition #3): True direction
     // 9 bits. Metric = degree true. Scale = 0. Ref = 9
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302047 -> 020054 (Repetition #3): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (True direction from which clouds are moving, 9bits)';
     $i++;
     // 008002: Vertical significance (surface observations)
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '008002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Vertical significance, 6bits)';
     $i++;
     // 3 02 048: Direction and elevation of cloud
     // 302048 -> 005021: Bearing of azimuth
     // 16 bits. Metric = degree. Scale = 2. Ref = 0
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302048 -> 005021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Bearing of azimuth, 16bits)';
     $i++;
     // 302048 -> 007021: Elevation
     // 15 bits. Metric = Degree. Scale = 2. Ref = -9000.
     $this->report_parts[$s][$i] = '111111111111111';
     $this->explanations[$s][$i][] = '302048 -> 007021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Elevation, 15bits)';
     $i++;
     // 302048 -> 020012: Cloud type
     // 6 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111';
     $this->explanations[$s][$i][] = '302048 -> 020012: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Cloud type, 6bits)';
     $i++;
     // 302048 -> 005021: Bearing of azimuth
     // 16 bits. Metric = degree. Scale = 2. Ref = 0
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302048 -> 005021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Bearing of azimuth, 16bits)';
     $i++;
     // 302048 -> 007021: Elevation
     // 15 bits. Metric = Degree. Scale = 2. Ref = -9000.
     $this->report_parts[$s][$i] = '111111111111111';
     $this->explanations[$s][$i][] = '302048 -> 007021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Elevation, 15bits)';
     $i++;
     // 3 02 037: State of ground, snow depth, ground minimum temperature
     // 302037 -> 020062: State of the ground
     // 5 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '11111';
     // 31 - missing value from "State of ground" code table.
     $this->explanations[$s][$i][] = '302037 -> 020062: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (State of the ground, 5bits)';
     $i++;
     // 302037 -> 013013: Total snow depth
     // 16 bits. Metric = m. Scale = 2. Ref = -2.
     if (isset($this->sensors['snow_depth'])) {
         if ($this->sensors['snow_depth']['is_m']) {
             $this->report_parts[$s][$i] = '1111111111111111';
             $this->explanations[$s][$i][] = '302037 -> 013013: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Last data about Snow Depth is unavailable</span> (Total snow depth, 16bits)';
         } else {
             $value = round($this->sensors['snow_depth']['sensor_feature_value'] * 100) + 2;
             $this->report_parts[$s][$i] = $this->prepare_binary_value($value, 16);
             $this->explanations[$s][$i][] = '302037 -> 013013: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $value . '</span> (Total snow depth, 16bits)';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111111111';
         $this->explanations[$s][$i][] = '302037 -> 013013: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Total snow depth, 16bits)';
     }
     $i++;
     // 302037 -> 012113: Ground minimum temperature
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302037 -> 012113: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Ground minimum temperature, 16bits)';
     $i++;
     // 0 12 122: Ground minimum temperature of the preceding night
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '0 12 122: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Ground minimum temperature of the preceding night, 16bits)';
     $i++;
     // 0 13 056: Character and intensity of precipitation
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 13 056: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Character and intensity of precipitation, 4bits)';
     $i++;
     // 0 13 057: Time of beginning or end of precipitation
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 13 057: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time of beginning or end of precipitation, 4bits)';
     $i++;
     // -- Locust data --
     // 0 20 101: Locust (acridian) name
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 101: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Locust (acridian) name, 4bits)';
     $i++;
     // 0 20 102: Locust (maturity) colour
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 102: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Locust (maturity) colour, 4bits)';
     $i++;
     // 0 20 103: Stage of development of locusts
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 103: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Stage of development of locusts, 4bits)';
     $i++;
     // 0 20 104: Organization state of swarm or band of locusts
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 104: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Organization state of swarm or band of locusts, 4bits)';
     $i++;
     // 0 20 105: Size of swarm or band of locusts and duration of passage of swarm
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 105: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Size of swarm or band of locusts and duration of passage of swarm, 4bits)';
     $i++;
     // 0 20 106: Locust population density
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 106: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Locust population density , 4bits)';
     $i++;
     // 0 20 107: Direction of movements of locust swarm
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 107: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Direction of movements of locust swarm, 4bits)';
     $i++;
     // 0 20 108: Extent of vegetation
     // 4 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '0 20 108: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Extent of vegetation, 4bits)';
     $i++;
     // -- End of Locust data --
     // 3 02 043: Basic  synoptic “Period” data
     // 3 02 043 → 3 02 038: Present and past weather.
     // 302043 -> 302038 -> 020003: Present weather
     // 9 bits. Metric = Code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302043 -> 302038 -> 020003: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> Present weather, 9bits)';
     $i++;
     // SEE NOTE 1!
     // 302043 -> 302038 -> 004024: Time period of displacement
     // 12 bits. Metric = Hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302038 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time period of displacement, 12bits)';
     $i++;
     // 302043 -> 302038 -> 020004: Past Weather 1
     // 5 bits. Metric = -. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '11111';
     $this->explanations[$s][$i][] = '302043 -> 302038 -> 020004: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Past Weather 1, 5bits)';
     $i++;
     // SEE NOTE 2!
     // 302043 -> 302038 -> 020005: Past Weather 2
     // 5 bits. Metric = Code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '11111';
     $this->explanations[$s][$i][] = '302043 -> 302038 -> 020005: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Past Weather 2, 5bits)';
     $i++;
     // SEE NOTE 3!
     // 3 02 043 → 3 02 039: Sunshine data (from 1 hour and 24 hour period)
     // 302043 -> 302039 -> 004024 (Repetition #1): Time period of sunshine measuring
     // 12 bits.  Metric = Hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $this->prepare_binary_value(2047, 12);
     $this->explanations[$s][$i][] = '302043 -> 302039 -> 004024 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>-1 - (-2048) = 2047</span> (Time period of sunshine measuring, hours,  12 bits)';
     $i++;
     // 302043 -> 302039 -> 014031 (Repetition #1): Total Sunshine
     // 11 bits. Metric = minute. Scale = 0. Ref = 0.
     if (isset($this->sensors['sun_duration_in_period']) && $this->sensors['sun_duration_in_period']['sensor_feature_period']) {
         if ($this->sensors['sun_duration_in_period']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111';
             $expl_val = '<span>Last data about Sunshine is unavailable</span>';
         } else {
             // get object of SunDuration handler
             $handler_obj = SensorHandler::create($this->sensors['sun_duration_in_period']['handler_id_code']);
             // get total sunshine in last 1 hour
             $last_1_hr = $handler_obj->getTotalInLastXHr($this->sensors['sun_duration_in_period']['sensor_feature_id'], $script_runtime, 1, false)['total'];
             // round to get integer
             $str_tmp = round($last_1_hr);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 11);
             $expl_val = '<span>' . $str_tmp . ' (during last hour)</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $expl_val = '<span>No sunshine sensor</span>';
     }
     $this->explanations[$s][$i][] = '302043 -> 302039 -> 014031 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Total Sunshine, minutes, 11bits)';
     $i++;
     // 302043 -> 302039 -> 004024 (Repetition #2): Time period of sunshine measuring
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = '100000011000';
     $this->explanations[$s][$i][] = '302043 -> 302039 -> 004024 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>24 - (-2048) = 2072</span> (Time period of sunshine measuring, hrs, 12bits)';
     $i++;
     // 302043 -> 302039 -> 014031 (Repetition #2): Total Sunshine
     // 11 bits. Metric = minute. Scale = 0. Ref = 0.
     if (isset($this->sensors['sun_duration_in_period']) && $this->sensors['sun_duration_in_period']['sensor_feature_period']) {
         $handler_obj = SensorHandler::create($this->sensors['sun_duration_in_period']['handler_id_code']);
         $last_24_hr = $handler_obj->getTotalInLastXHr($this->sensors['sun_duration_in_period']['sensor_feature_id'], $measuring_timestamp, 24, false)['total'];
         $str_tmp = round($last_24_hr);
         $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 11);
         $expl_val = '<span>' . $str_tmp . '</span>';
     } else {
         $this->report_parts[$s][$i] = '11111111111';
         $this->explanations[$s][$i][] = '<span>No sunshine sensor</span>';
     }
     $this->explanations[$s][$i][] = '302043 -> 302039 -> 014031 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Total Sunshine, minutes, 11bits)';
     $i++;
     // 3 02 043 → 3 02 040: Precipitation measurement
     // 302043 -> 302040 -> 007032: Height of rain sensor
     // 16 bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302040 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of rain sensor, 16bits)';
     $i++;
     // 302043 -> 302040 -> 004024 (Repetition #1): Time period or displacement
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = $this->prepare_binary_value(2047, 12);
     $this->explanations[$s][$i][] = '302043 -> 302040 -> 004024 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>-1 - (-2048) = 2049</span> (Time period or displacemnt, Hours, 12bits)';
     $i++;
     // 302043 -> 302040 -> 013011 (Repetition #1): Total rain for 1 hour
     // 14 bits. Metric = kg/m2. Scale = 1. Ref = -1.
     if (isset($this->sensors['rain_in_period']) && $this->sensors['rain_in_period']['sensor_feature_period']) {
         if ($this->sensors['rain_in_period']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111111';
             $expl_val = '<span>last data from Rain sensor is unavalable.</span>';
         } else {
             // create object of Rain handler
             $handler_obj = SensorHandler::create($this->sensors['rain_in_period']['handler_id_code']);
             // get total rain in last 1 hour
             $last_1_hr = $handler_obj->getTotalInLastXHr($this->sensors['rain_in_period']['sensor_feature_id'], $script_runtime, 1, false)['total'];
             $tmp1 = It::convertMetric($last_1_hr, $this->sensors['rain_in_period']['metric_code'], 'millimeter');
             // 1. apply scale = -2 (value * 10^1 )
             // 2. round to get integer
             // 3. apply ref = -1
             $tmp = round($tmp1 * 10) - -1;
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 14);
             $expl_val = '<span>' . $last_1_hr . ' ' . $this->sensors['rain_in_period']['metric_code'] . ' (during 60 min)';
             if ($this->sensors['rain_in_period']['metric_code'] != 'millimeter') {
                 $expl_val .= ' = ' . $tmp1 . ' mm ';
             }
             $expl_val .= ' ~ round(' . $tmp1 . ' * 10^1) -(-1) = ' . $tmp . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111';
         $expl_val = '<span>No rain sensor</span>';
     }
     $this->explanations[$s][$i][] = '302043 -> 302040 -> 013011 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . '(Total rain for 1 hour, 14bits)';
     $i++;
     // The following descriptors about rain depend on script run timestamp.
     // At 00:00 report shows total rain for last 24 hours.
     // At 06:00, 12:00, 18:00 report shows total rain for last 6 hours.
     // For any other timestamp report shows missed value (111...)
     $rain_total_hours = 0;
     if ($script_runtime_minute == '00' && $script_runtime_hour == '00') {
         $rain_total_hours = 24;
     } else {
         if ($script_runtime_minute == '00' && in_array($script_runtime_hour, array('06', '12', '18'))) {
             $rain_total_hours = 6;
         }
     }
     // 302043 -> 302040 -> 004024 (Repetition #2): Time period of precipitation measuring
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = $rain_total_hours ? $this->prepare_binary_value(2048 - $rain_total_hours, 12) : '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302040 -> 004024 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . ($rain_total_hours ? '-' . $rain_total_hours . ' - (-2048)' : 'This is not 00, 06, 12 or 18 hr') . '</span> (Time period of precipitation measuring, hrs, 12bits)';
     $i++;
     // 302043 -> 302040 -> 013011 (Repetition #2): Total precipitation in last 24 or 6 hours
     // 14bits. Metric = kg/m2. Scale = 1. Ref = -1.
     if (isset($this->sensors['rain_in_period'])) {
         if ($rain_total_hours === 0) {
             $this->report_parts[$s][$i] = '11111111111111';
             $expl_val = '<span>Total rain can be calculated only at 00, 06, 12 or 18 hr</span>';
         } else {
             // create object of rain Handler
             $handler_obj = SensorHandler::create($this->sensors['rain_in_period']['handler_id_code']);
             $rain_last_24_hr = $handler_obj->getTotalInLastXHr($this->sensors['rain_in_period']['sensor_feature_id'], $script_runtime, $rain_total_hours, false)['total'];
             $tmp = It::convertMetric($rain_last_24_hr, $this->sensors['rain_in_period']['metric_code'], 'millimeter');
             // 1. apply scale = -2 (value * 10^1 )
             // 2. round to get integer
             // 3. apply ref = -1
             $tmp_str = round($tmp * 10) - -1;
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp_str, 14);
             $expl_val = '<span>';
             $expl_val .= $rain_last_24_hr . ' ' . $this->sensors['rain_in_period']['metric_code'];
             if ($this->sensors['rain_in_period']['metric_code'] != 'millimeter') {
                 $expl_val .= ' = ' . $tmp . ' mm';
             }
             $expl_val .= '~ round(' . $tmp . ' * 10^1) -(-1) = ' . $tmp_str . '</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111';
         $expl_val = '<span>No rain sensor</span>';
     }
     $this->explanations[$s][$i][] = '302043 -> 302040 -> 013011 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span>  => ' . $expl_val . ' (Total precipitation past ' . $rain_total_hours . ' hours, kg/m2, 14bits)';
     $i++;
     // 3 02 043 -> 3 02 041: Extreme temperature data
     // 302043 -> 302041 -> 007032: Height of temperature sensor
     // 16 bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of temperature sensor, 16bits)';
     $i++;
     // prepare temperature extremums
     if (isset($this->sensors['temperature'])) {
         $handler_obj = SensorHandler::create($this->sensors['temperature']['handler_id_code']);
         if ($script_runtime_hour == '06') {
             // get temperature extremums in period [21:00 of day before previous day; 21:00 of previous day)
             $tmp_measuring_timestamp = mktime(20, 59, 59, $script_runtime_month, $script_runtime_day - 1, $script_runtime_year);
             $temperature_extr = $handler_obj->getMaxMinFromHour($this->sensors['temperature']['sensor_feature_id'], $tmp_measuring_timestamp, 21, false);
         } else {
             if ($script_runtime_hour == '00') {
                 // get temperature extremums in period [09:00 of previous day; 09:00 of this day)
                 $tmp_measuring_timestamp = mktime(8, 59, 59, $script_runtime_month, $script_runtime_day - 1, $script_runtime_year);
                 $temperature_extr = $handler_obj->getMaxMinFromHour($this->sensors['temperature']['sensor_feature_id'], $tmp_measuring_timestamp, 9, false);
             }
         }
     }
     // Max tempr
     // 302043 -> 302041 -> 004024: Time period of temperature measuring
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $script_runtime_hour == '06' && $script_runtime_minute == '00' ? '011111100100' : '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>24 * 10^0 - (-2048) = 2072</span> (Time period of temperature measuring, hours, 12bits)';
     $i++;
     // 302043 -> 302041 -> 004024: Time period of temperature measuring
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $script_runtime_hour == '06' && $script_runtime_minute == '00' ? '011111111100' : '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time period or replacement, 12bits)';
     $i++;
     // 302043 -> 302041 -> 012111: Maximum temperature, at height and over period specified
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     if (isset($this->sensors['temperature'])) {
         if ($script_runtime_hour == '06' && $script_runtime_minute == '00') {
             $tmp1 = It::convertMetric($temperature_extr['max'] ? $temperature_extr['max'] : 0, $this->sensors['temperature']['metric_code'], 'kelvin');
             // 1. apply scale = 2 (value * 10^2)
             // 2. round to get integer
             $tmp = round($tmp1 * 100);
             $this->report_parts[$s][$i] = ($tmp > 0 ? '0' : '1') . $this->prepare_binary_value(abs($tmp), 15);
             $expl_val = $temperature_extr['max'] . ' ' . $this->sensors['temperature']['metric_code'];
             if ($this->sensors['temperature']['metric_code'] != 'kelvin') {
                 $expl_val .= ' = ' . $tmp1 . ' kelvin';
             }
             $expl_val .= ' ~ |round(' . $tmp1 . ' * 10^2) - 0| = ' . $tmp . '(+left bit = ' . ($tmp > 0 ? '0' : '1') . ' because ' . ($tmp > 0 ? 'positive' : 'negative') . ') ';
         } else {
             $this->report_parts[$s][$i] = '1111111111111111';
             $expl_val = 'MAX tempr can be calculated only at 06UTC';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111111111';
         $expl_val = 'No temperature sensor';
     }
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 012111: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Maximum temperature, K, 16bits)';
     $i++;
     // Min tempr
     // 302043 -> 302041 -> 004024: Time period of temperature measuring
     $this->report_parts[$s][$i] = $script_runtime_hour == '06' && $script_runtime_minute == '00' ? '011111100100' : '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . ($script_runtime_hour == '06' && $script_runtime_minute == '00' ? '-28 - (-2048) = 2020' : 'Missed because it is not at 00 UTC') . '</span> (Time period of temperature measuring, 12bits)';
     $i++;
     // 302043 -> 302041 -> 004024: Time period of temperature measuring
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $script_runtime_hour == '06' && $script_runtime_minute == '00' ? '011111111100' : '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . ($script_runtime_hour == '06' && $script_runtime_minute == '00' ? '-4 - (-2048) = 2044' : 'Missed because it is not at 00 UTC') . '</span> (Time period or displacement, 12bits)';
     $i++;
     // 302043 -> 302041 -> 012112: Minimum temperature, at height and over period specified
     // 16 bits. Metric = K. Scale = 2. Ref = 0.
     if (isset($this->sensors['temperature'])) {
         if ($script_runtime_hour == '06' && $script_runtime_minute == '00') {
             $tmp1 = It::convertMetric($temperature_extr['min'] ? $temperature_extr['min'] : 0, $this->sensors['temperature']['metric_code'], 'kelvin');
             // 1. apply scale = 2 (value * 10^2)
             // 2. round to get integer
             $tmp = round($tmp1 * 100);
             $this->report_parts[$s][$i] = ($tmp > 0 ? '0' : '1') . $this->prepare_binary_value(abs($tmp), 15);
             $expl_val = $temperature_extr['min'] . ' ' . $this->sensors['temperature']['metric_code'];
             if ($this->sensors['temperature']['metric_code'] != 'kelvin') {
                 $expl_val .= ' = ' . $tmp1 . ' kelvin';
             }
             $expl_val .= ' ~ |round(' . $tmp1 . ' * 10^2) - 0| = ' . abs($tmp) . ' (+left bit = ' . ($tmp > 0 ? '0' : '1') . ' because ' . ($tmp > 0 ? 'positive' : 'negative') . ')';
         } else {
             $this->report_parts[$s][$i] = '1111111111111111';
             $expl_val = 'MIN tempr can be calculated only at 00UTC';
         }
     } else {
         $this->report_parts[$s][$i] = '1111111111111111';
         $expl_val = 'No temperature sensor';
     }
     $this->explanations[$s][$i][] = '302043 -> 302041 -> 012112: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Minimum temperature, K, 16bits)';
     $i++;
     // 3 02 043 -> 3 02 042:  Wind data
     // 302043 -> 302042 -> 007032: Height of wind sensor
     // 16 bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of wind sensor, 16bits)';
     $i++;
     // 302043 -> 302042 -> 002002: Type of instrumentation for wind measurement
     // 4 bits. Metric = Flag table. Scale = 0. Ref = 0
     $this->report_parts[$s][$i] = $this->prepare_binary_value(8, 4);
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 002002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>8</span> (Type of instrumentation for wind measurement, 4 bits)';
     $i++;
     // 302043 -> 302042 -> 008021: Time significance
     // 5 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = $this->prepare_binary_value(2, 5);
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 008021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>2=time averaged</span> (Time significance, 5 bits)';
     $i++;
     // 302043 -> 302042 -> 004025: Time period or displacement
     // 12 bits. Metric = minute. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $this->prepare_binary_value(2038, 12);
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 004025: <span>' . $this->report_parts[$s][$i] . '</span> => <span>-10 - (-2048) = 2038</span> (Time period or displacement, min, 12bits)';
     $i++;
     // 302043 -> 302042 -> 011001: Wind direction
     // 9 bits. Metric = degree. Scale = 0. Ref = 0.
     if (isset($this->sensors['wind_direction_10'])) {
         if ($this->sensors['wind_direction_10']['is_m']) {
             $this->report_parts[$s][$i] = '111111111';
             $expl_val = 'Last data about Wind Direction is unavailable';
         } else {
             // create object of wind direction handler
             $handler_obj = SensorHandler::create($this->sensors['wind_direction_10']['handler_id_code']);
             // apply magnetic north offset
             $tmp = $handler_obj->applyOffset($this->sensors['wind_direction_10']['sensor_feature_value'], $this->station_info->magnetic_north_offset);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 9);
             $expl_val = $this->sensors['wind_direction_10']['sensor_feature_value'];
         }
     } else {
         $this->report_parts[$s][$i] = '111111111';
         $expl_val = 'No Wind Direction sensor';
     }
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011001: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Wind direction, degree, 9 bits)';
     $i++;
     // 302043 -> 302042 -> 011002: Wind speed
     // 12 bits. Metric = m/s. Scale = 1. Ref = 0.
     if (isset($this->sensors['wind_speed_10'])) {
         if ($this->sensors['wind_speed_10']['is_m']) {
             $this->report_parts[$s][$i] = '111111111111';
             $expl_val = 'Last data about Wind Speed is unavailable';
         } else {
             $tmp1 = It::convertMetric($this->sensors['wind_speed_10']['sensor_feature_value'], $this->sensors['wind_speed_10']['metric_code'], 'meter_per_second');
             // 1. apply scale = 1 (value * 10)
             // 2. round to get integer
             $tmp = round($tmp1 * 10);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 12);
             $expl_val = $this->sensors['wind_speed_10']['sensor_feature_value'] . ' ' . $this->sensors['wind_speed_10']['metric_code'];
             if ($this->sensors['wind_speed_10']['metric_code'] != 'meter_per_second') {
                 $expl_val .= ' = ' . $tmp1 . ' meter_per_second';
             }
             $expl_val .= ' ~ round(' . $tmp1 . ' * 10^1) = ' . $tmp;
         }
     } else {
         $this->report_parts[$s][$i] = '111111111111';
         $expl_val = 'No Wind Speed sensor';
     }
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011002: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Wind speed, m/s, 12bits)';
     $i++;
     // 302043 -> 302042 -> 008021: Time significance
     // 5 bits. Metric = code table. Scale = 0. Ref =0 .
     $this->report_parts[$s][$i] = '11111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 008021: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time significance, 5bits)';
     $i++;
     // 302043 -> 302042 -> 004025 (Repetition #1): Time of preiod or displacement
     // 12 bits. Metric = minute. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 004025 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time of preiod or displacement, min, 12 bits)';
     $i++;
     // 302043 -> 302042 -> 011043 (Repetition #1): Maximum wind gust direction
     // 9 bits. Metric = degree. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011043 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Maximum wind gust direction, degree, 9 bits)';
     $i++;
     // 302043 -> 302042 -> 011041 (Repetition #1): Maximum wind gust speed
     // 12 bits. Metric = m/s. Scale = 1. Ref = 0.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011041 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Maximum wind gust speed, 12 bits)';
     $i++;
     // 302043 -> 302042 -> 004025 (Repetition #2): Time of preiod or displacement
     // 12 bits. Metric = minute. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 004025 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time of preiod or displacement, min, 12 bits)';
     $i++;
     // 302043 -> 302042 -> 011043 (Repetition #2): Maximum wind gust direction
     // 9 bits. Metric = degree. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011043 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Maximum wind gust direction, degree, 9 bits)';
     $i++;
     // 302043 -> 302042 -> 011041 (Repetition #2): Maximum wind gust speed
     // 12 bits. Metric = m/s. Scale = 1. Ref = 0.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302043 -> 302042 -> 011041 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Maximum wind gust speed, 12 bits)';
     $i++;
     // ADDED BLOCK!
     // 302043 -> 007032: Height of sensor above local ground
     // 16 bits. Metric = m. Scale = 2. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111111111';
     $this->explanations[$s][$i][] = '302043 -> 007032: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Height of sensor above local ground (or deck of marine platform, 16 bits)';
     $i++;
     // END OF ADDED BLOCK!
     // 3 02 044: Evaporation data
     // 302044 -> 004024: Time period or displacement
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302044 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time period or displacement, Hour, 12 bits)';
     $i++;
     // 302044 -> 002004: Type of instrumentation for evaporation measurement or type of crop for which evapotranspiration is reported
     // 4 bits. Metric = code table. Scale = 0. Ref = 0.
     $this->report_parts[$s][$i] = '1111';
     $this->explanations[$s][$i][] = '302044 -> 002004: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Type of ..., 4bits)';
     $i++;
     // 302044 -> 013033: Evaporation/evapotranspiration
     // 10 bits. Metric = kg/m2. Scale = 1. Ref = 0.
     $this->report_parts[$s][$i] = '1111111111';
     $this->explanations[$s][$i][] = '302044 -> 013033: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing (Evaporation/evapotranspiration, 10bits)</span>';
     $i++;
     // 3 02 045: Radiation data (from 1 hour and 24 hour period)
     // 302045 -> 004024 (Repetition #1): Time period or displacement
     // 12 bits. Metric = hour. Scale = 0. Ref = 2048.
     $this->report_parts[$s][$i] = $this->prepare_binary_value(2047, 12);
     $this->explanations[$s][$i][] = '302045 -> 004024 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>-1 - (-2048) = 2047</span> (Time period or displacement, Hour, 12 bits)';
     $i++;
     // 302045 -> 014002 (Repetition #1): Long-wave radiation
     // 17 bits. Metric: J/m2. Scale = -3. Ref = -65536.
     $this->report_parts[$s][$i] = '11111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014002 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Long-wave radiation, 17 bits)';
     $i++;
     // 302045 -> 014004 (Repetition #1): Short-wave radiation
     // 17 bits. Metric: J/m2. Scale = -3. Ref = -65536.
     $this->report_parts[$s][$i] = '11111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014004 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Short-wave radiation, 17 bits)';
     $i++;
     // 302045 -> 014016 (Repetition #1): Net radiation
     // 15 bits. Metric: J/m2. Scale = -4. Ref = -16384
     $this->report_parts[$s][$i] = '111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014016 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Net radiation, 15 bits)';
     $i++;
     // 302045 -> 014028 (Repetition #1): Global solar radiation
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     if (isset($this->sensors['solar_radiation_in_period']) && $this->sensors['solar_radiation_in_period']['sensor_feature_period']) {
         if ($this->sensors['solar_radiation_in_period']['is_m']) {
             $this->report_parts[$s][$i] = '11111111111111111111';
             $expl_val = 'Last data about Sun Radiation is unavailable';
         } else {
             // create object of Solar Radiation Handler
             $handler_obj = SensorHandler::create($this->sensors['solar_radiation_in_period']['handler_id_code']);
             // get total radiation in last 1 hr
             $last_1_hr = $handler_obj->getTotalInLastXHr($this->sensors['solar_radiation_in_period']['sensor_feature_id'], $script_runtime, 1, false)['total'];
             $tmp1 = It::convertMetric($last_1_hr, $this->sensors['solar_radiation_in_period']['metric_code'], 'joule_per_sq_meter');
             $tmp = round($tmp1 / 100);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 20);
             $expl_val = $tmp1 . ' ' . $this->sensors['solar_radiation_in_period']['metric_code'] . ' (during 60 min)';
             if ($this->sensors['solar_radiation_in_period']['metric_code'] != 'joule_per_sq_meter') {
                 $expl_val .= ' = ' . $tmp1 . ' joule_per_sq_meter (during 60 min)';
             }
             $expl_val .= ' ~ round(' . $tmp1 . ' * 10^(-2)) = ' . $tmp;
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111111111';
         $expl_val = 'No Sun Radiation sensor';
     }
     $this->explanations[$s][$i][] = '302045 -> 014028 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (Global solar radiation, J/m2, 20 bits)';
     $i++;
     // 302045 -> 014029 (Repetition #1): Diffuse solar radiation
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     $this->report_parts[$s][$i] = '11111111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014029 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Diffuse solar radiation, 20 bits)';
     $i++;
     // 302045 -> 014030 (Repetition #1): Direct solar radiation
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     $this->report_parts[$s][$i] = '11111111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014030 (Repetition #1): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Direct solar radiation, 20 bits)';
     $i++;
     // 302045 -> 004024 (Repetition #2): Time period or displacement (24 hr only for report at 00:00. Miss for other times)
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048
     $this->report_parts[$s][$i] = $script_runtime_hour == '06' && $script_runtime_minute == '00' ? '011111101000' : '111111111111';
     $this->explanations[$s][$i][] = '302045 -> 004024 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . ($script_runtime_hour == '06' && $script_runtime_minute == '00' ? '(-24) - (-2048) = 2024' : 'Missing, It is not 06UTC') . '</span> (Time period or displacement, Hour, 12 bits)';
     $i++;
     // 302045 -> 014002 (Repetition #2): Long-wave radiation
     // 17 bits. Metric: J/m2. Scale = -3. Ref = -65536.
     $this->report_parts[$s][$i] = '11111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014002 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Long-wave radiation, 17 bits)';
     $i++;
     // 302045 -> 014004 (Repetition #2): Short-wave radiation
     // 17 bits. Metric: J/m2. Scale = -3. Ref = -65536.
     $this->report_parts[$s][$i] = '11111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014004 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Short-wave radiation, 17 bits)';
     $i++;
     // 302045 -> 014016 (Repetition #2): Net radiation
     // 15 bits. Metric: J/m2. Scale = -4. Ref = -16384
     $this->report_parts[$s][$i] = '111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014016 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Net radiation, 15 bits)';
     $i++;
     // 302045 -> 014028 (Repetition #2): GLOBAL SOLAR RADIATION
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     if (isset($this->sensors['solar_radiation_in_period'])) {
         if ($script_runtime_hour == '06' && $script_runtime_minute == '00') {
             // create object of Solar Radiation Handler
             $handler_obj = SensorHandler::create($this->sensors['solar_radiation_in_period']['handler_id_code']);
             // get total radiation in last 24 hr
             $last_24_hr = $handler_obj->getTotalInLastXHr($this->sensors['solar_radiation_in_period']['sensor_feature_id'], $script_runtime, 24, false)['total'];
             $tmp1 = It::convertMetric($last_24_hr, $this->sensors['solar_radiation_in_period']['metric_code'], 'joule_per_sq_meter');
             $tmp = round($tmp1 / 100);
             $this->report_parts[$s][$i] = $this->prepare_binary_value($tmp, 20);
             $expl_val = $last_24_hr . ' ' . $this->sensors['solar_radiation_in_period']['metric_code'];
             if ($this->sensors['solar_radiation_in_period']['metric_code'] != 'joule_per_sq_meter') {
                 $expl_val .= ' = ' . $tmp1 . ' joule_per_sq_meter';
             }
             $expl_val .= ' ~ round(' . $tmp1 . ' * 10^(-2)) = ' . $tmp;
         } else {
             $this->report_parts[$s][$i] = '11111111111111111111';
             $expl_val = '24hr radiation can be calculated only at 06UTC';
         }
     } else {
         $this->report_parts[$s][$i] = '11111111111111111111';
         $expl_val = 'No Sun Radiation sensor';
     }
     $this->explanations[$s][$i][] = '302045 -> 014028 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $expl_val . '</span> (GLOBAL SOLAR RADIATION, J/m2, 20 bits)';
     $i++;
     // 302045 -> 014029 (Repetition #2): Diffuse solar radiation
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     $this->report_parts[$s][$i] = '11111111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014029 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Diffuse solar radiation, 20 bits)';
     $i++;
     // 302045 -> 014030 (Repetition #2): Direct solar radiation
     // 20 bits. Metric = J/m2. Scale = -2. Ref = 0.
     $this->report_parts[$s][$i] = '11111111111111111111';
     $this->explanations[$s][$i][] = '302045 -> 014030 (Repetition #2): <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Direct solar radiation, 20 bits)';
     $i++;
     // 3 02 046: Temperature change
     // 302046 -> 004024: Time period or displacement
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302046 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time period or displacement, Hour, 12 bits)';
     $i++;
     // 302046 -> 004024: Time period or displacement
     // 12 bits. Metric = hour. Scale = 0. Ref = -2048.
     $this->report_parts[$s][$i] = '111111111111';
     $this->explanations[$s][$i][] = '302046 -> 004024: <span>' . $this->report_parts[$s][$i] . '</span> => <span>Missing</span> (Time period or displacement, Hour, 12 bits)';
     $i++;
     // 302046 -> 012049: Temperature change over period specified
     // 6 bits. Metric = K. Scale = 0. Ref = -30.
     if (isset($this->sensors['temperature']) && isset($sensors_24hr_ago['temperature'])) {
         if ($script_runtime_minute == '00' && in_array($script_runtime_hour, array('00', '03', '06', '09', '12', '15', '18', '21'))) {
             if ($this->sensors['temperature']['is_m']) {
                 $this->report_parts[$s][$i] = '111111';
                 $expl_val = 'Data about last Temperature is unavailable';
             } else {
                 if ($sensors_24hr_ago['temperature']['is_m']) {
                     $this->report_parts[$s][$i] = '111111';
                     $expl_val = 'Data about 24h ago Temperature is unavailable';
                 } else {
                     $tmp1 = It::convertMetric($this->sensors['temperature']['sensor_feature_value'], $this->sensors['temperature']['metric_code'], 'kelvin');
                     $tmp2 = It::convertMetric($sensors_24hr_ago['temperature']['sensor_feature_value'], $sensors_24hr_ago['temperature']['metric_code'], 'kelvin');
                     $str_tmp = abs(round($tmp1 - $tmp2)) + 30;
                     $this->report_parts[$s][$i] = $this->prepare_binary_value($str_tmp, 6);
                     $expl_val = 'Last Tempr = ' . round($this->sensors['temperature']['sensor_feature_value'], 1) . ' ' . $this->sensors['temperature']['metric_code'] . ' (' . round($tmp1, 1) . ' kelvin)';
                     $expl_val .= '; 24h ago Tempr = ' . round($sensors_24hr_ago['temperature']['sensor_feature_value'], 1) . ' ' . $sensors_24hr_ago['temperature']['metric_code'] . ' (' . round($tmp2, 1) . ' kelvin)';
                     $expl_val .= '; |Last - 24h| = |' . ($tmp1 - $tmp2) . '| ~ ' . abs(round($tmp1 - $tmp2));
                     $expl_val .= '; Apply ref.value -30: <span>' . (abs(round($tmp1 - $tmp2)) + 30) . '</span>';
                 }
             }
         } else {
             $this->report_parts[$s][$i] = '111111';
             $expl_val = '<span>It is not 06UTC. Total 24h Sunshine is calculated only at 06:00UTC</span>';
         }
     } else {
         $this->report_parts[$s][$i] = '111111';
         $expl_val = 'No Temperature sensor';
     }
     $this->explanations[$s][$i][] = '302046 -> 012049: <span>' . $this->report_parts[$s][$i] . '</span> => ' . $expl_val . ' (Temperature change over period specified, K, 6 bits)';
     $i++;
     $concatenated = implode('', $this->report_parts[$s]);
     $reminder = fmod(strlen($concatenated), 8);
     $this->report_parts[$s][$i] = str_pad('0', 8 - $reminder, '0', STR_PAD_LEFT);
     $this->explanations[$s][$i][] = 'Extra <span>' . (8 - $reminder) . '</span> bits to make int count of octets in section 4: <span>' . $this->report_parts[$s][$i] . '</span>';
     $s = 4;
     $i = 0;
     $concatenated = implode('', $this->report_parts[$s]);
     $total = strlen($concatenated) / 8;
     /// ??? RECALCULATE !!!!
     $this->report_parts[$s][$i] = $this->prepare_binary_value($total, 24);
     $this->explanations[$s][$i][0] = 'Octets 1-3: <span>' . $this->report_parts[$s][$i] . '</span> => <span>' . $total . '</span> (length of section4 in octets)';
     $i++;
 }
Ejemplo n.º 8
0
 protected function _prepareListenerLogInfo()
 {
     $this->_logger->log(__METHOD__);
     if (!is_null($this->schedule_process_info)) {
         $criteria = new CDbCriteria();
         $criteria->compare('station_id', $this->schedule_info->station_id);
         $criteria->compare('failed', '0');
         $criteria->compare('measuring_timestamp', '>=' . $this->schedule_process_info->check_period_start);
         $criteria->compare('measuring_timestamp', '<=' . $this->schedule_process_info->check_period_end);
         $criteria->order = 'measuring_timestamp desc, log_id desc';
         $this->_logger->log(__METHOD__ . 'measuring_timestamp' . '>=' . $this->schedule_process_info->check_period_start);
         $this->_logger->log(__METHOD__ . 'measuring_timestamp' . '<=' . $this->schedule_process_info->check_period_end);
         if (in_array($this->schedule_info->report_type, array('bufr', 'synop', 'metar', 'speci'))) {
             $criteria->limit = '1';
             $logRecord = ListenerLog::model()->find($criteria);
             //				$this->schedule_process_info->listener_log_id = is_null($logRecord) ? 0 : $logRecord->log_id;
             //				$this->schedule_process_info->save();
             $this->listener_log_info = $logRecord;
             $this->_logger->log(__METHOD__ . ' $this->listener_log_info' . print_r($this->listener_log_info, 1));
             if (is_null($this->listener_log_info)) {
                 $this->errors[] = 'Listener log info (#' . $this->schedule_process_info->listener_log_id . ') can not be found';
                 return false;
             }
         } else {
             $logRecords = ListenerLog::model()->findAll($criteria);
             if (count($logRecords) > 0) {
                 $logIds = array();
                 foreach ($logRecords as $logRecord) {
                     $logIds[] = $logRecord->log_id;
                 }
                 $this->listener_log_info = $logRecords;
                 $this->schedule_process_info->listener_log_ids = implode(',', $logIds);
                 $this->schedule_process_info->save();
             } else {
                 $this->listener_log_info = null;
                 $this->schedule_process_info->listener_log_ids = '';
                 $this->schedule_process_info->save();
                 $this->errors[] = 'Listener log info (#' . $this->schedule_process_info->listener_log_id . ') can not be found';
                 return false;
             }
         }
     }
     return true;
 }
Ejemplo n.º 9
0
 public function prepareList($page_size = 10)
 {
     $stations = $this->getAllStations();
     if ($stations) {
         $sql_where = array();
         //---------------- Start groupping
         $use_field = '';
         if ($this->rate_volume == 1) {
             $use_field = 'sensor_value';
         } else {
             if ($this->rate_volume == 5) {
                 $use_field = '5min_sum';
                 $tmp = array('00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55');
             } else {
                 if ($this->rate_volume == 10) {
                     $use_field = '10min_sum';
                     $tmp = array('00', '10', '20', '30', '40', '50');
                 } else {
                     if ($this->rate_volume == 20) {
                         $use_field = '20min_sum';
                         $tmp = array('00', '20', '40');
                     } else {
                         if ($this->rate_volume == 30) {
                             $use_field = '30min_sum';
                             $tmp = array('00', '30');
                         } else {
                             if ($this->rate_volume == 60) {
                                 $use_field = '60min_sum';
                                 $tmp = array('00');
                             }
                         }
                     }
                 }
             }
             $sql_where[] = "DATE_FORMAT(`sd`.`measuring_timestamp`, '%i') IN ('" . implode("','", $tmp) . "')";
         }
         $sql_where[] = "`sd`.`" . $use_field . "` > 0";
         //---------------- End groupping
         //---------------- Start date filter
         if ($this->date_from) {
             $sql_where[] = "`sd`.`measuring_timestamp` >= '" . date('Y-m-d H:i:s', strtotime($this->date_from . ' ' . $this->time_from)) . "'";
         }
         if ($this->date_to) {
             $sql_where[] = "`sd`.`measuring_timestamp` <= '" . date('Y-m-d H:i:s', strtotime($this->date_to . ' ' . $this->time_to)) . "'";
         }
         //---------------- End date filter
         //---------------- Start Station filter
         if ($this->station_id) {
             $sql_where[] = "`sd`.`station_id` = '" . $this->station_id . "'";
         } else {
             $sql_groupped_table = "SELECT `sensor_id`, MAX(`measuring_timestamp`) AS `MaxDateTime` FROM `" . SensorDataMinute::model()->tableName() . "` WHERE `" . $use_field . "` > 0 ";
             if ($this->date_from) {
                 $sql_groupped_table .= " AND `measuring_timestamp` >= '" . date('Y-m-d H:i:s', strtotime($this->date_from . ' ' . $this->time_from)) . "' ";
             }
             if ($this->date_to) {
                 $sql_groupped_table .= " AND `measuring_timestamp` <= '" . date('Y-m-d H:i:s', strtotime($this->date_to . ' ' . $this->time_to)) . "' ";
             }
             $sql_groupped_table .= " GROUP BY `sensor_id` ";
             $sql = "SELECT `tt`.`sensor_data_id`\n                        FROM `" . SensorDataMinute::model()->tableName() . "` `tt`\n                        INNER JOIN ( {$sql_groupped_table} ) `groupedtt` ON `tt`.`sensor_id` = `groupedtt`.`sensor_id` AND `tt`.`measuring_timestamp` = `groupedtt`.`MaxDateTime`";
             $last_values = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryColumn();
             if (!$last_values) {
                 $last_values = array(0);
             }
             $sql_where[] = "`sd`.`station_id` IN (" . implode(',', array_keys($stations)) . ") AND `sd`.`sensor_data_id` IN (" . implode(',', $last_values) . ")";
         }
         //---------------- End Station filter
         if ($page_size > 0) {
             $sql = "SELECT COUNT(*)\n                        FROM `" . SensorDataMinute::model()->tableName() . "` `sd`\n                        WHERE " . implode(' AND ', $sql_where);
             $total = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryScalar();
             $pages = new CPagination($total);
             $pages->pageSize = $page_size;
             //$pages->applyLimit($criteria);
         }
         if ($this->order_field == 'date') {
             $sql_order = "`sd`.`measuring_timestamp` " . $this->order_direction;
         } elseif ($this->order_field == 'name') {
             $sql_order = "`st`.`display_name` " . $this->order_direction;
         } elseif ($this->order_field == 'lasttx') {
             $sql_order = "`sd`.`" . $use_field . "` " . $this->order_direction;
         } elseif ($this->order_field == 'lasthr') {
             $sql_order = "`sd`.`60min_sum` " . $this->order_direction;
         } elseif ($this->order_field == 'last24hr') {
             $sql_order = "`sd`.`1day_sum` " . $this->order_direction;
         }
         $sql = "SELECT `st`.`display_name`,\n                           `st`.`station_id_code`,\n                           `st`.`station_id`,\n\n                           `ll`.`message`,\n                           `ll`.`log_id`,\n\n                           `sd`.`sensor_data_id`,\n                           `sd`.`battery_voltage`,\n                           `sd`.`sensor_id`,\n                           `sd`.`measuring_timestamp`,\n                            DATE_FORMAT(`sd`.`measuring_timestamp`, '%m/%d/%Y') AS `tx_date_formatted`,\n                            DATE_FORMAT(`sd`.`measuring_timestamp`, '%H:%i') AS `tx_time_formatted`,\n                           `sd`.`sensor_value`,\n                           `sd`.`5min_sum`,\n                           `sd`.`10min_sum`,\n                           `sd`.`20min_sum`,\n                           `sd`.`30min_sum`,\n                           `sd`.`60min_sum`,\n                           `sd`.`1day_sum`,\n\n                           `sd`.`bucket_size`,\n                           `sd`.`1day_sum` AS `day_value_mm`,\n                           `sd`.`60min_sum` AS `hour_value_mm`\n\n                    FROM `" . SensorDataMinute::model()->tableName() . "` `sd`\n                    LEFT JOIN `" . ListenerLog::model()->tableName() . "` `ll` ON `sd`.`listener_log_id` = `ll`.`log_id`\n                    LEFT JOIN `" . Station::model()->tableName() . "`     `st` ON `st`.`station_id` = `sd`.`station_id`\n\n                    WHERE " . implode(' AND ', $sql_where) . "\n                    ORDER BY {$sql_order} ";
         if ($page_size) {
             $sql .= " LIMIT " . $pages->currentPage * $pages->pageSize . ", " . $pages->pageSize;
         }
         $res = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         if ($res) {
             $total_found = count($res);
             foreach ($res as $key => $value) {
                 $res[$key]['battery_voltage_formatted'] = $value['battery_voltage'] / 10;
                 $res[$key]['tx_value_mm'] = $value[$use_field] * $value['bucket_size'];
                 $res[$key]['tx_value_rate_mm'] = $value[$use_field] * $value['bucket_size'] * 60 / $this->rate_volume;
                 $res[$key]['day_value_mm'] = $value['day_value_mm'] * $value['bucket_size'];
                 $res[$key]['hour_value_mm'] = $value['hour_value_mm'] * $value['bucket_size'];
                 $res[$key]['period'] = $this->rate_volume;
                 $hour_value_id = date('YmdH', strtotime($value['measuring_timestamp']));
                 $res[$key]['hour_value_id'] = $hour_value_id;
                 $res[$key]['hour_value_rate_mm'] = 0;
                 if ($stations[$value['station_id']]['filter_limit_max'] > 0) {
                     if ($res[$key]['tx_value_mm'] >= $stations[$value['station_id']]['filter_limit_max']) {
                         $res[$key]['filter_errors'][] = "R >= <b>" . $stations[$value['station_id']]['filter_limit_max'] . "</b>  ";
                     }
                 }
                 if ($stations[$value['station_id']]['filter_limit_min'] > 0) {
                     if ($res[$key]['tx_value_mm'] <= $stations[$value['station_id']]['filter_limit_min']) {
                         $res[$key]['filter_errors'][] = "R <= <b>" . $stations[$value['station_id']]['filter_limit_min'] . "</b>  ";
                     }
                 }
                 if ($stations[$value['station_id']]['filter_limit_diff'] > 0) {
                     if ($key != 0 && abs($res[$key]['tx_value_mm'] - $res[$key - 1]['tx_value_mm']) >= $stations[$value['station_id']]['filter_limit_diff']) {
                         $res[$key]['filter_errors'][] = "|R - R0| >= <b>" . $stations[$value['station_id']]['filter_limit_diff'] . "</b> ";
                     }
                 }
             }
             foreach ($res as $key => $value) {
                 if ($key != 0 && $res[$key]['hour_value_id'] != $res[$key - 1]['hour_value_id']) {
                     $res[$key - 1]['hour_value_rate_mm'] = $res[$key - 1]['hour_value_mm'];
                 } elseif ($key == $total_found - 1) {
                     $res[$key]['hour_value_rate_mm'] = $res[$key]['hour_value_mm'];
                 }
             }
         }
     }
     return array('list' => $res, 'pages' => $pages);
 }
Ejemplo n.º 10
0
 public function actionScheduleStationHistory()
 {
     $station_to_report_id = isset($_REQUEST['station_to_report_id']) ? intval($_REQUEST['station_to_report_id']) : null;
     if (!$station_to_report_id) {
         $this->redirect($this->createUrl('site/schedule'));
     }
     $criteria = new CDbCriteria();
     $criteria->condition = 'sr_to_s_id = :sr_to_s_id';
     $criteria->params = array(':sr_to_s_id' => $station_to_report_id);
     $criteria->order = 'schedule_processed_id DESC';
     $count = ScheduleReportProcessed::model()->count($criteria);
     $pages = new CPagination($count);
     $pages->pageSize = 15;
     $pages->applyLimit($criteria);
     $scheduleProcessed = ScheduleReportProcessed::model()->with('listenerLog', 'ScheduleReportToStation.schedule_report', 'ScheduleReportToStation.realStation')->findAll($criteria);
     $files_path = dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR . "files" . DIRECTORY_SEPARATOR . "schedule_reports";
     $scheduleProcessedFormatted = array();
     foreach ($scheduleProcessed as $key => $value) {
         $scheduleProcessedFormatted[$key] = $value->attributes;
         $scheduleProcessedFormatted[$key]['report_type'] = $value->ScheduleReportToStation['schedule_report']['report_type'];
         $scheduleProcessedFormatted[$key]['report_format'] = $value->ScheduleReportToStation['schedule_report']['report_format'];
         $scheduleProcessedFormatted[$key]['station_id'] = $value->ScheduleReportToStation->station_id;
         $scheduleProcessedFormatted[$key]['measuring_timestamp'] = $value->listenerLog['measuring_timestamp'];
         $scheduleProcessedFormatted[$key]['message'] = $value->listenerLog->message;
         if ($scheduleProcessedFormatted[$key]['serialized_report_errors']) {
             $scheduleProcessedFormatted[$key]['report_errors'] = unserialize($scheduleProcessedFormatted[$key]['serialized_report_errors']);
         }
         if ($scheduleProcessedFormatted[$key]['serialized_report_explanations']) {
             $scheduleProcessedFormatted[$key]['report_explanations'] = unserialize($scheduleProcessedFormatted[$key]['serialized_report_explanations']);
         }
         if (in_array($value->ScheduleReportToStation['schedule_report']['report_type'], array('synop', 'metar', 'speci')) && file_exists($files_path . DIRECTORY_SEPARATOR . $scheduleProcessedFormatted[$key]['schedule_processed_id'])) {
             $scheduleProcessedFormatted[$key]['report_string_initial'] = file_get_contents($files_path . DIRECTORY_SEPARATOR . $scheduleProcessedFormatted[$key]['schedule_processed_id']);
         }
         if ($scheduleProcessedFormatted[$key]['listener_log_ids']) {
             $sql = "SELECT t2.log_id, t2.message, t2.measuring_timestamp\n                                FROM  `" . ListenerLog::model()->tableName() . "` t2\n                                WHERE t2.log_id IN (" . $scheduleProcessedFormatted[$key]['listener_log_ids'] . ")\n                                ORDER BY `t2`.`measuring_timestamp` DESC";
             $scheduleProcessedFormatted[$key]['logs'] = Yii::app()->db->createCommand($sql)->queryAll();
         }
     }
     $reportInfo = $scheduleProcessed[0]->ScheduleReportToStation['schedule_report']->attributes;
     $stationInfo = $scheduleProcessed[0]->ScheduleReportToStation->realStation->attributes;
     $this->render('schedule_report_history', array('scheduleProcessed' => $scheduleProcessedFormatted, 'stationInfo' => $stationInfo, 'reportInfo' => $reportInfo, 'pages' => $pages));
 }
Ejemplo n.º 11
0
 protected function listenDLTorrent($cycle = 1)
 {
     $this->_logger->log(__METHOD__, array('cycle' => $cycle));
     $this->_connector->setParams(array('timeout' => 60));
     ListenerProcess::addComment($this->listener->listener_id, 'comment', 'Opening COM connection');
     $messages = null;
     $process = $this;
     $logger = $process->_logger;
     $this->_connector->onReceiveMessage = function ($message) use(&$process, &$logger) {
         $logger->log(__METHOD__ . ' New message', array('message' => $message, 'listener_id' => $process->listener->listener_id, 'overwrite' => $process->settings->overwrite_data_on_listening));
         $messageId = ListenerLog::addNew($message, $process->listener->listener_id, $process->settings->overwrite_data_on_listening, 'datalogger');
         ListenerProcess::addComment($process->listener->listener_id, 'comment', 'got msg #' . $messageId);
     };
     $result = $this->_connector->readData($messages);
     $this->_logger->log(__METHOD__ . ' Complete listen datalogger.', array('cycle' => $cycle, 'result' => $result));
 }
Ejemplo n.º 12
0
 /**
  * parses message and adds parsed values to database
  */
 function logMessage()
 {
     $this->_logger->log(__METHOD__);
     if ($this->_station->timezone_id) {
         TimezoneWork::set($this->_station->timezone_id);
         //            TimezoneWork::setReverse($this->_station->timezone_id);
     }
     // saves measuring timestamp
     $measuring_timestamp = mktime(substr($this->_tx_time, 0, 2), substr($this->_tx_time, 2, 2), 0, substr($this->_tx_date, 2, 2), substr($this->_tx_date, 4, 2), substr($this->_tx_date, 0, 2));
     //        if ($this->_station->timezone_id){
     //            $measuring_timestamp = TimezoneWork::setTimeByLocalTz($this->_station->timezone_id,$measuring_timestamp);
     //        }
     $this->message_obj->measuring_timestamp = date('Y-m-d H:i:s', $measuring_timestamp);
     $this->_logger->log(__METHOD__ . " measuring_timestamp: " . $measuring_timestamp);
     $this->_logger->log(__METHOD__ . " date: " . $this->message_obj->measuring_timestamp);
     $this->message_obj->save();
     // there are different ways to parse LOG message and REGULAR message
     if ($this->_message_type === 'rg_log') {
         // LOG provides us with info from only 1 sensor (however RG station can have more sensors)
         $sensor_info = $this->getFirstRGSensor();
         if ($sensor_info !== false) {
             $save_data_params = array('listener_log_id' => $this->message_obj->log_id, 'rewrite_prev_values' => $this->message_obj->rewrite_prev_values, 'battery_voltage' => $this->rg_battery_voltage, 'sensor' => $sensor_info['sensor'], 'sensor_features' => $sensor_info['features']);
             // create object of sensor handler
             $handler_obj = SensorHandler::create('RainRgLog');
             // parse part of message which is going just after sensor ID.
             // prepare data pairs basing on this string
             $res = $handler_obj->prepareDataPairs($this->_body, $measuring_timestamp, $sensor_info['features']);
             if ($res === false) {
                 $this->pushWarning('incorrect_sensor_value_format', 'Handler ' . $sensor_info['sensor']->sensor_id_code . ' can not get data from "' . $this->_body . '"');
                 //continue;
             }
             // save prepared sensor's data
             $handler_obj->saveDataPairs($save_data_params);
         }
     } else {
         // parse body into pairs SensorId::DataString
         $message_sensors_strings = $this->parseSensorsValues($this->_body);
         if (is_array($message_sensors_strings) && count($message_sensors_strings) > 0) {
             $save_data_params = array('listener_log_id' => $this->message_obj->log_id, 'rewrite_prev_values' => $this->message_obj->rewrite_prev_values, 'battery_voltage' => $this->rg_battery_voltage);
             foreach ($message_sensors_strings as $message_sensor_string) {
                 // get sensor's info by sensor ID code
                 $sensor_info = $this->getSensorInfo($message_sensor_string[0]);
                 if (!is_null($sensor_info)) {
                     $save_data_params['sensor'] = $sensor_info['sensor'];
                     $save_data_params['sensor_features'] = $sensor_info['features'];
                     // create object of sensor handler
                     $handler_obj = SensorHandler::create($sensor_info['sensor']->handler->handler_id_code);
                     $handler_obj->loadAWSFormat($this->_station->aws_format);
                     // parse string coming after sensor ID into data pairs (feature:value)
                     $res = $handler_obj->prepareDataPairs($message_sensor_string[1], $measuring_timestamp, $sensor_info['features']);
                     if ($res === false) {
                         $this->pushWarning('incorrect_sensor_value_format', 'Handler ' . $message_sensor_string[0] . ' can not get data from "' . $message_sensor_string[1] . '"');
                         continue;
                     }
                     // save features values
                     $handler_obj->saveDataPairs($save_data_params);
                     // some actions can be done after data is saved (depends on handler)
                     $handler_obj->afterDataPairsSaved($save_data_params);
                 }
             }
         }
     }
 }
Ejemplo n.º 13
0
 private function prepareListenerLogInserts($limit_timestamp)
 {
     $result_sql = "";
     $sql = "SELECT * \n                FROM `" . ListenerLog::model()->tableName() . "`\n                WHERE `created` <= '" . $limit_timestamp . "' \n                LIMIT 0, 50";
     $res = Yii::app()->db->createCommand($sql)->queryAll();
     $total = count($res);
     $ids = array();
     if ($res) {
         $fields = array();
         foreach ($res[0] as $key2 => $value2) {
             $fields[] = $key2;
         }
         $sql_header = "INSERT IGNORE INTO `" . ListenerLog::model()->tableName() . "` (`" . implode('`,`', $fields) . "`) VALUES ";
         $result_sql = $sql_header;
         foreach ($res as $key => $value) {
             $ids[] = $value['log_id'];
             $result_sql .= "('" . implode("','", $value) . "')";
             if ($key + 1 < $total) {
                 $result_sql .= ", ";
             }
         }
         $this->addBackupLog(count($ids) . " inserts for ListenerLog");
     }
     return array($ids, $result_sql);
 }
Ejemplo n.º 14
0
 public function m_0_4_1()
 {
     @apache_setenv('no-gzip', 1);
     @ini_set('zlib.output_compression', 0);
     @ini_set('implicit_flush', 1);
     ini_set('memory_limit', '-1');
     //ob_start();
     $this->flushNotification('...Please wait... Updating is going on... DO NOT LEAVE THIS PAGE!');
     $this->flushNotification('<br/>...Going to add "is_last" fields to `listener_log` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . ListenerLog::model()->tableName() . "` LIKE 'is_last'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `" . ListenerLog::model()->tableName() . "` ADD `is_last` tinyint(1) NOT NULL DEFAULT '0' AFTER `is_processed`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $stations = Yii::app()->db->createCommand("SELECT * FROM `" . Station::model()->tableName() . "`")->queryAll();
         if ($stations) {
             foreach ($stations as $key => $value) {
                 ListenerLog::updateIsLastForStation($value['station_id']);
             }
         }
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... not need');
     }
     $this->flushNotification('<br/>...Going to add "is_processing" column to `listener_log` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . ListenerLog::model()->tableName() . "` LIKE 'is_processing'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `" . ListenerLog::model()->tableName() . "` ADD `is_processing` TINYINT(1) NOT NULL DEFAULT '0' AFTER `is_processed`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... not need');
     }
     // station
     $this->flushNotification('<br/><br/>Station table:');
     $this->flushNotification('<br/>...Going to update  "national_aws_number" field at `station` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . Station::model()->tableName() . "` LIKE 'national_aws_number'")->queryAll();
     if ($res[0]['Null'] == 'NO') {
         Yii::app()->db->createCommand("ALTER TABLE `station` CHANGE `national_aws_number` `national_aws_number`  int(11) DEFAULT '0'")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... not need');
     }
     $this->flushNotification('<br/>...Going to add new column "country_id" to `station` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . Station::model()->tableName() . "` LIKE 'country_id'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `station` ADD `country_id` int(11) NOT NULL DEFAULT '0' AFTER `magnetic_north_offset`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     $this->flushNotification('<br/>...Going to add new column "city_id" to `station` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . Station::model()->tableName() . "` LIKE 'city_id'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `station` ADD `city_id` int(11) NOT NULL DEFAULT '0' AFTER `country_id`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     $this->flushNotification('<br/>...Going to add new column "timezone_offset" to `station` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . Station::model()->tableName() . "` LIKE 'timezone_offset'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `station` ADD `timezone_offset` varchar(20) NOT NULL AFTER `timezone_id`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     $this->flushNotification('<br/>...Going to update "timezone_offset" data in `station` table...');
     $sql = "SELECT `station_id`, `timezone_id` FROM `" . Station::model()->tableName() . "` WHERE `timezone_offset` = ''";
     $res = Yii::app()->db->createCommand($sql)->queryAll();
     if ($res) {
         foreach ($res as $key => $value) {
             $sql = "UPDATE `" . Station::model()->tableName() . "` SET `timezone_offset` = '" . TimezoneWork::getOffsetFromUTC($value['timezone_id'], 1) . "' WHERE `station_id` = '" . $value['station_id'] . "'";
             Yii::app()->db->createCommand($sql)->query();
         }
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... not need');
     }
     $this->flushNotification('<br/>...Going to add new column "awos_msg_source_folder" to `station` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `" . Station::model()->tableName() . "` LIKE 'awos_msg_source_folder'")->queryAll();
     if (!$res) {
         Yii::app()->db->createCommand("ALTER TABLE `station` ADD `awos_msg_source_folder` TEXT CHARACTER SET ucs2 COLLATE ucs2_general_ci NOT NULL AFTER `city_id`")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     // Sensor Data
     $this->flushNotification('<br/>...Going to update `sensor_data` table\'s data...');
     Yii::app()->db->createCommand("UPDATE `sensor_data` SET `period` = 1440 WHERE `period` = 86400")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     //Schedule report
     $this->flushNotification('<br/>...Going to create `schedule_report` table...');
     $tables = array();
     $res = Yii::app()->db->createCommand("SHOW TABLES")->queryAll();
     if ($res) {
         foreach ($res as $key => $value) {
             foreach ($value as $k1 => $v1) {
                 $tables[] = $v1;
             }
         }
     }
     if (!in_array('schedule_report', $tables)) {
         $sql = "CREATE TABLE `schedule_report` (\n                      `schedule_id` int(11) NOT NULL AUTO_INCREMENT,\n                      `report_type` varchar(50) NOT NULL DEFAULT 'synop' COMMENT 'synop, bufr',\n                      `station_id` int(11) NOT NULL,\n                      `period` int(11) NOT NULL DEFAULT '60' COMMENT 'in minutes',\n                      `method` varchar(20) NOT NULL DEFAULT 'email' COMMENT 'email, ftp',\n                      `destination_email` varchar(255) NOT NULL,\n                      `destination_ip` varchar(15) NOT NULL,\n                      `destination_ip_port` int(5) NOT NULL DEFAULT '21',\n                      `destination_ip_folder` varchar(255) NOT NULL DEFAULT '/',\n                      `destination_ip_user` varchar(255) NOT NULL,\n                      `destination_ip_password` varchar(255) NOT NULL,\n                      `report_format` varchar(20) NOT NULL DEFAULT 'csv' COMMENT 'txt, csv',\n                      `last_scheduled_run_fact` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      `last_scheduled_run_planned` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      `created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      `updated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      PRIMARY KEY (`schedule_id`)\n                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
         Yii::app()->db->createCommand($sql)->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     $this->flushNotification('<br/>...Going to create `schedule_report_processed` table...');
     if (!in_array('schedule_report_processed', $tables)) {
         $sql = "CREATE TABLE `schedule_report_processed` (\n                      `schedule_processed_id` int(11) NOT NULL AUTO_INCREMENT,\n                      `schedule_id` int(11) NOT NULL,\n                      `listener_log_id` int(11) NOT NULL,\n                      `is_processed` tinyint(1) NOT NULL DEFAULT '0',\n                      `report_string_initial` text NOT NULL,\n                      `report_string_changed` text NOT NULL,\n                      `serialized_report_problems` text NOT NULL,\n                      `serialized_report_errors` text NOT NULL,\n                      `serialized_report_explanations` text NOT NULL,\n                      `is_last` tinyint(1) NOT NULL DEFAULT '0',\n                      `created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      `updated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n                      PRIMARY KEY (`schedule_processed_id`),\n                      KEY `schedule_id` (`schedule_id`),\n                      KEY `listener_log_id` (`listener_log_id`),\n                      CONSTRAINT `schedule_report_processed_fk` FOREIGN KEY (`schedule_id`) REFERENCES `schedule_report` (`schedule_id`) ON DELETE CASCADE ON UPDATE NO ACTION,\n                      CONSTRAINT `schedule_report_processed_ibfk_1` FOREIGN KEY (`listener_log_id`) REFERENCES `listener_log` (`log_id`) ON DELETE CASCADE ON UPDATE NO ACTION\n                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
         Yii::app()->db->createCommand($sql)->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     // metrics
     $this->flushNotification('<br/><br/>New Metrics:');
     $this->flushNotification('<br/>...Going to add new metric "kJ/sq.m" ...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_metric` (`metric_id`, `html_code`, `short_name`, `full_name`, `code`) VALUES ('21', 'kJ/sq.m', 'kJ/sq.m', 'Kilo Joule per square meter', 'kjoule_per_sq_meter')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new metric "feet"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_metric` (`metric_id`, `html_code`, `short_name`, `full_name`, `code`) VALUES ('22', 'ft', 'ft', 'Feet', 'feet')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new metric "km"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_metric` (`metric_id`,`html_code`,`short_name`,`full_name`,`code`) VALUES (23 , 'km', 'km', 'Kilometer', 'kilometer')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "solar radiation" and "kj/sq.m"...');
     RefbookMeasurementTypeMetric::model()->deleteByPk(23);
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES ('23', '9', '21', '0')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new measuring type "Cloud Vertical Visibility"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type` (`measurement_type_id`, `display_name`, `code`, `ord`) VALUES (16 ,'Cloud Vertical Visibility', 'cloud_vertical_visibility', '14')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new measuring type "Cloud Height" ...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type` (`measurement_type_id`, `display_name`, `code`, `ord`) VALUES (17, 'Cloud Height', 'cloud_height', 15)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new measuring type "Sea Level" ...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type` (`measurement_type_id`, `display_name`, `code`, `ord`) VALUES (18 , 'Sea Level (Mean, Sigma, Wave Hight)', 'sea_level', '16')")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add relation between "Cloud Vertical Visibility" and "ft" ...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (24,16,22,1)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "Cloud Vertical Visibility" and "meter"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (25,16,11,0)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "Cloud Height" and "ft"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (26,17,22,1)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "Cloud Height" and "meter"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (27,17,11,0)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "Visibility" and "meter"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (28, 11, 11, 1)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to add new relation between "Sea Level" and "meter"...');
     Yii::app()->db->createCommand("INSERT INTO `refbook_measurement_type_metric` (`measurement_type_metric_id`, `measurement_type_id`, `metric_id`, `is_main`) VALUES (29, 18, 11, 1)")->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     // sensor handler
     $this->flushNotification('<br/>...Going to add new column "awos_station_uses" to `sensor_handler` table...');
     $res = Yii::app()->db->createCommand("SHOW COLUMNS FROM `sensor_handler` LIKE 'awos_station_uses'")->queryAll();
     if (!$res) {
         $res = Yii::app()->db->createCommand("ALTER TABLE `sensor_handler` ADD `awos_station_uses` TINYINT( 1 ) NOT NULL DEFAULT '0'")->query();
         Yii::app()->db->createCommand("COMMIT")->query();
         $this->flushNotification(' ... done');
     } else {
         $this->flushNotification(' ... already exists');
     }
     $this->flushNotification('<br/>...Going to update `sensor_handler` table...');
     $sql = "UPDATE `sensor_handler` SET \n                `handler_id_code` = 'SeaLevelAWS',\n                `display_name` = 'Sea Level and Tide Data',\n                `description` = 'Handler \"Sea Level and Tide Data\" : Processes string like \"SL1XXXXYYYYZZZZ\", where <br/>SL1 - device Id; <br/>XXXX - Mean value;<br/>YYYY - Sigma value; <br/>ZZZZ - Wave Height <br/>Example: SL1179017900140 = SL1 sensor sent data: Mean value = 1.79, Sigma value = 1.79, Wave height = 140m.',\n                `default_prefix` = 'SL',\n                `aws_station_uses` = 1,\n                `rain_station_uses` = 0,\n                `awos_station_uses` = 0,\n                `aws_single_group` = 'sea_level'\n                WHERE `handler_id` = 13";
     Yii::app()->db->createCommand($sql)->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $sql = "UPDATE `sensor_handler` SET \n                `handler_id_code` = 'VisibilityAWS',\n                `display_name` = 'Visibility',\n                `description` = 'Handler \"Visibility\"',\n                `default_prefix` = 'VI',\n                `aws_station_uses` = 1,\n                `rain_station_uses` = 0,\n                `awos_station_uses` = 0,\n                `aws_single_group` = 'visibility'\n                WHERE `handler_id` = 14";
     Yii::app()->db->createCommand($sql)->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $sql = "UPDATE `sensor_handler` SET `handler_id_code` = 'CloudHeightAWS',\n                `display_name` = 'Cloud Height',\n                `description` = 'Handler \"Cloud Height\"',\n                `default_prefix` = 'CH',\n                `aws_station_uses` = 1,\n                `rain_station_uses` = 0,\n                `awos_station_uses` = 0,\n                `aws_single_group` = 'clouds'\n                WHERE `handler_id` = 15";
     Yii::app()->db->createCommand($sql)->query();
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $this->flushNotification('<br/>...Going to update calculation_handler table...');
     $res = Yii::app()->db->createCommand("UPDATE `calculation_handler` SET `display_name` = 'Pressure Adjusted to MSL' WHERE `handler_id` = 2");
     Yii::app()->db->createCommand("COMMIT")->query();
     $this->flushNotification(' ... done');
     $bat_path = dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'at' . DIRECTORY_SEPARATOR . 'schedule.bat';
     $schedule_bat_content = getConfigValue('php_exe_path') . " -f  " . dirname(Yii::app()->request->scriptFile) . DIRECTORY_SEPARATOR . "console.php schedule";
     file_put_contents($bat_path, $schedule_bat_content);
     exec('schtasks /create /sc minute /mo 1 /F /ru "SYSTEM" /tn delaircoScheduleScript /tr ' . $bat_path, $output);
     $values = getConfigValue('schedule');
     $values['each_minute_process_id'] = 'delaircoScheduleScript';
     InstallConfig::setConfigSection('schedule', $values);
     $values = getConfigValue('path');
     $values['site_url_for_console'] = It::baseUrl();
     InstallConfig::setConfigSection('path', $values);
     It::memStatus('update__success');
     $this->flushNotification('<script type="text/javascript"> setTimeout(function(){document.location.href="' . Yii::app()->controller->createUrl('update/index') . '"}, 10000)</script>');
 }
Ejemplo n.º 15
0
 public function process($path)
 {
     if (!file_exists($path)) {
         throw new Exception('Can\'t find file ' . $path);
     }
     $pathinfo = pathinfo($path);
     $base_filename = $pathinfo['basename'];
     $xml_content = file_get_contents($path);
     if (!strlen($xml_content)) {
         throw new Exception($base_filename . " is empty");
     }
     libxml_use_internal_errors(true);
     $sxe = simplexml_load_string($xml_content);
     $error_str = "";
     if ($sxe === false) {
         foreach (libxml_get_errors() as $error) {
             $error_str .= "\n" . $error->message;
         }
         throw new Exception($error_str);
     }
     // XML must contain 1 RUNWAY tag
     if (count($sxe->RUNWAY) > 1) {
         throw new Exception('XML ' . $base_filename . ' contains ' . count($sxe->RUNWAY) . ' RUNWAY tags');
     }
     if (count($sxe->RUNWAY) == 0) {
         throw new Exception('XML ' . $base_filename . ' doesn\'t contain RUNWAY tags');
     }
     // RUNWAY's "NAME" attribute must be "08/26"
     if ($sxe->RUNWAY['NAME'] != '08/26') {
         throw new Exception('XML ' . $base_filename . ' RUNWAY name = "' . $sxe->RUNWAY['NAME'] . '", "08/26" was expected');
     }
     // RUNWAY must contain at least 1 ZONE tag
     if (count($sxe->RUNWAY->ZONE) == 0) {
         throw new Exception('XML ' . $base_filename . ' doesn\'t contain ZONE tags');
     }
     // XML must contain "UNITS" tag
     if (!isset($sxe->UNITS)) {
         throw new Exception('XML ' . $base_filename . ' doesn\'t contain UNITS section');
     }
     $str = '';
     $possible_units = array('WIND' => 'kt', 'VISBILITY' => 'meters', 'RVR' => 'meters', 'ALTIMETER' => 'hpa');
     foreach ($possible_units as $key => $value) {
         if (!isset($sxe->UNITS->{$key})) {
             $str .= ($str ? '; ' : '') . ' UNITS[' . $key . '] is missed';
         } else {
             if ($sxe->UNITS->{$key} != $value) {
                 $str .= ($str ? '; ' : '') . ' unknown metric "' . $sxe->UNITS->{$key} . '" in UNITS[' . $key . ']';
             }
         }
     }
     if ($str) {
         throw new Exception($str);
     }
     $result = array();
     $messages = array();
     for ($key = 0; $key < count($sxe->RUNWAY->ZONE); $key++) {
         // Get's Station ID
         if ($sxe->RUNWAY->ZONE[$key]['NAME'] == '08') {
             $messages[$key]['station_id_code'] = 'AWS08';
         } else {
             if ($sxe->RUNWAY->ZONE[$key]['NAME'] == '26') {
                 $messages[$key]['station_id_code'] = 'AWS26';
             } else {
                 continue;
             }
         }
         //Gets sensor's data from tags:
         // WIND SPEED
         if (isset($sxe->RUNWAY->ZONE[$key]->WSPD_5SEC)) {
             $messages[$key]['sensors']['WindSpeed'][0]['wind_speed_1'] = (string) $sxe->RUNWAY->ZONE[$key]->WSPD_5SEC;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->WSPD_2MIN)) {
             $messages[$key]['sensors']['WindSpeed'][0]['wind_speed_2'] = (string) $sxe->RUNWAY->ZONE[$key]->WSPD_2MIN;
         }
         // WIND DIRECTION
         if (isset($sxe->RUNWAY->ZONE[$key]->WDIR_5SEC)) {
             $messages[$key]['sensors']['WindDirection'][0]['wind_direction_1'] = (string) $sxe->RUNWAY->ZONE[$key]->WDIR_5SEC;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->WDIR_2MIN)) {
             $messages[$key]['sensors']['WindDirection'][0]['wind_direction_2'] = (string) $sxe->RUNWAY->ZONE[$key]->WDIR_2MIN;
         }
         // TEMPERATURE
         if (isset($sxe->RUNWAY->ZONE[$key]->TEMP_5MIN)) {
             $messages[$key]['sensors']['Temperature'][0]['temperature'] = (string) $sxe->RUNWAY->ZONE[$key]->TEMP_5MIN;
         }
         // HUMIDITY
         if (isset($sxe->RUNWAY->ZONE[$key]->HUM_5MIN)) {
             $messages[$key]['sensors']['Humidity'][0]['humidity'] = (string) $sxe->RUNWAY->ZONE[$key]->HUM_5MIN;
         }
         // PRESSURE
         if (isset($sxe->RUNWAY->ZONE[$key]->PRESSURE1)) {
             $messages[$key]['sensors']['Pressure'][0]['pressure'] = (string) $sxe->RUNWAY->ZONE[$key]->PRESSURE1;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->PRESSURE2)) {
             $messages[$key]['sensors']['Pressure'][1]['pressure'] = (string) $sxe->RUNWAY->ZONE[$key]->PRESSURE2;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->PRESSURE3)) {
             $messages[$key]['sensors']['Pressure'][2]['pressure'] = (string) $sxe->RUNWAY->ZONE[$key]->PRESSURE3;
         }
         // CLOUD
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDRANGE)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_measuring_range'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDRANGE;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDVV)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_vertical_visibility'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDVV;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDH1)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_height_1'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDH1;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDH2)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_height_2'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDH2;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDH3)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_height_3'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDH3;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDD1)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_depth_1'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDD1;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDD2)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_depth_2'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDD2;
         }
         if (isset($sxe->RUNWAY->ZONE[$key]->CLOUDD3)) {
             $messages[$key]['sensors']['CloudHeightAWS'][0]['cloud_height_depth_3'] = (string) $sxe->RUNWAY->ZONE[$key]->CLOUDD3;
         }
         // VISIBILITY
         $vis = (string) $sxe->RUNWAY->ZONE[$key]->EXC;
         if (isset($sxe->RUNWAY->ZONE[$key]->EXC) && is_numeric($vis) && $vis != 0) {
             //P = (1/σ) x ln (1/0.05)
             //where ln is the log to base e or the natural logarithm. σ  is the extinction cooefficient.
             //This number will be in km, so we will need to multiply by 1000.
             $messages[$key]['sensors']['VisibilityAWS'][0]['visibility_1'] = 1 / $vis * log(20) * 1000;
         }
         // SOLAR
         if (isset($sxe->RUNWAY->ZONE[$key]->SOLAR_1MIN)) {
             $messages[$key]['sensors']['SolarRadiation'][0]['solar_radiation_in_period'] = (string) $sxe->RUNWAY->ZONE[$key]->SOLAR_1MIN;
         }
         // Rain fall
         if (isset($sxe->RUNWAY->ZONE[$key]->PRECIP_ACCUM)) {
             $messages[$key]['sensors']['RainAws'][0]['period'] = 5;
             $messages[$key]['sensors']['RainAws'][0]['rain_in_period'] = (string) $sxe->RUNWAY->ZONE[$key]->PRECIP_ACCUM;
         }
         // Sunshine duration
         if (isset($sxe->RUNWAY->ZONE[$key]->SUN_ACCUM)) {
             $messages[$key]['sensors']['SunshineDuration'][0]['period'] = 5;
             $messages[$key]['sensors']['SunshineDuration'][0]['sun_duration_in_period'] = (string) $sxe->RUNWAY->ZONE[$key]->SUN_ACCUM;
         }
     }
     if (!$messages) {
         $result[] = $base_filename . " : No datasets found";
         return implode("\n", $result);
     }
     $result[] = $base_filename . " : " . count($messages) . ' datasets were found';
     $sql = "SELECT * \n                FROM `" . Station::model()->tableName() . "` `t1`\n                WHERE `t1`.`station_id_code` IN ('AWS08', 'AWS26')";
     $res = Yii::app()->db->createCommand($sql)->queryAll();
     if (!$res) {
         $result[] = "AWS08 and AWS26 are not exist in database, no sense to convert XML into messages";
         return implode("\n", $result);
     }
     // for each stationID looks for sensors and features of this station
     $stations = array();
     foreach ($res as $key => $value) {
         $stations[$value['station_id_code']] = $value;
         $sql = "SELECT `t1`.`sensor_id_code`,\n                           `t1`.`station_id`,\n                           `t2`.`feature_code`,\n                           `t3`.`code` AS `metric_code`,\n                           `t4`.`handler_id_code`\n                    FROM `" . StationSensor::model()->tableName() . "` `t1`\n                    LEFT JOIN `" . StationSensorFeature::model()->tableName() . "` `t2` ON `t1`.`station_sensor_id` = `t2`.`sensor_id`\n                    LEFT JOIN `" . RefbookMetric::model()->tableName() . "`        `t3` ON `t3`.`metric_id` = `t2`.`metric_id`\n                    LEFT JOIN `" . SensorDBHandler::model()->tableName() . "`      `t4` ON `t4`.`handler_id` = `t1`.`handler_id`\n                    WHERE `t1`.`station_id` = '" . $value['station_id'] . "'\n                    ORDER BY `t4`.`handler_id_code` ASC, `t1`.`sensor_id_code` ASC";
         $res2 = Yii::app()->db->createCommand($sql)->queryAll();
         if ($res2) {
             $tmp = array();
             foreach ($res2 as $value2) {
                 $tmp[$value2['handler_id_code']][$value2['sensor_id_code']][$value2['feature_code']] = $value2['metric_code'];
             }
             foreach ($tmp as $key_handler => $value_sensors) {
                 foreach ($value_sensors as $key_sensor => $value_features) {
                     $stations[$value['station_id_code']]['sensors'][$key_handler][] = array('sensor_id_code' => $key_sensor, 'features' => $value_features);
                 }
             }
         }
     }
     $date_parsed = date_parse_from_format("D, j M Y H:i:s", $sxe->DATE);
     $date_prepared = mktime($date_parsed['hour'], $date_parsed['minute'], $date_parsed['second'], $date_parsed['month'], $date_parsed['day'], $date_parsed['year']);
     // convert parsed XML data into regular message
     // for this kind of messages we have an agreement to put X instead of D at the beginning of message.
     foreach ($messages as $key => $value) {
         if (!$stations[$value['station_id_code']]) {
             $result[] = $value['station_id_code'] . " station is not exists in database, no sense to convert RNWY part into message";
             continue;
         }
         $result_message_body = 'X' . $value['station_id_code'];
         $result_message_body .= date('ymdHi', $date_prepared);
         $result_message_body .= '00';
         // we need last_log for this satation to calculate period of measurement (some sensors' strings should contain this period
         $last_logs = ListenerLog::getLast2Messages($stations[$value['station_id_code']]['station_id']);
         if (isset($value['sensors'])) {
             foreach ($value['sensors'] as $key_handler => $value_sensors) {
                 if ($value_sensors) {
                     foreach ($value_sensors as $key_sensor => $value2) {
                         if (isset($stations[$value['station_id_code']]['sensors'][$key_handler][$key_sensor])) {
                             // create handler for each sensor (we parsed new data for)
                             $handler = SensorHandler::create($key_handler);
                             if ($key_handler == 'SolarRadiation' && $last_logs[0]['log_id']) {
                                 if ($last_logs[0]['log_id']) {
                                     $total_minutes = round(abs($date_prepared - strtotime($last_logs[0]['measuring_timestamp'])) / 60);
                                     $value2['period'] = $total_minutes;
                                 } else {
                                     $value2['period'] = 1;
                                 }
                                 if ($value2['solar_radiation_in_period'][0] != 'M') {
                                     $value2['solar_radiation_in_period'] = $value2['solar_radiation_in_period'] * $value2['period'] * 60;
                                 }
                             }
                             // each handler has it's own implementation of preparing sensors string for message basing on XML data
                             $res = $handler->prepareXMLValue($value2, $stations[$value['station_id_code']]['sensors'][$key_handler][$key_sensor]['features']);
                             $result_message_body .= $stations[$value['station_id_code']]['sensors'][$key_handler][$key_sensor]['sensor_id_code'] . $res;
                         }
                     }
                 }
             }
             $result_message_body .= It::prepareCRC($result_message_body);
             $result_message_body = '@' . $result_message_body . '$';
             // add new message into database. It will be processed later as all newcame messages
             $log_id = ListenerLog::addNew($result_message_body, 0, 1);
             $result[] = $base_filename . " : New message #" . $log_id . " was added";
         }
     }
     // return some comments created during convertation
     return implode("\n", $result);
 }
Ejemplo n.º 16
0
 protected function listen()
 {
     $this->_logger->log(__CLASS__ . ' ' . __METHOD__ . ' Start listen.', array('source' => $this->source));
     $messages = null;
     $process = $this;
     $logger = $process->_logger;
     $this->_connector->onReceiveMessage = function ($message, $station_id, $source_info) use(&$process, &$logger) {
         $logger->log(__CLASS__ . ' ' . __METHOD__ . ' New message', array('message' => $message, 'listener_id' => $process->listener->listener_id, 'overwrite' => $process->settings->overwrite_data_on_listening));
         $messageId = ListenerLog::addNew($message, $process->listener->listener_id, $process->settings->overwrite_data_on_listening, 'server', 0, $source_info);
         ListenerProcess::addComment($process->listener->listener_id, 'comment', 'got msg #' . $messageId);
     };
     $this->_connector->readData($messages);
     $this->_logger->log(__CLASS__ . ' ' . __METHOD__ . ' Complete listen.', array('source' => $this->source));
 }
Ejemplo n.º 17
0
 public function actionSetup()
 {
     $criteria = new CDbCriteria();
     $criteria->condition = "ord > 0";
     $criteria->order = "ord ASC";
     $meas_types = RefbookMeasurementType::model()->findAll($criteria);
     if ($meas_types) {
         foreach ($meas_types as $key => $value) {
             $sql = "SELECT `t1`.`metric_id`, CONCAT(`t2`.`html_code`, ' (', `t2`.`full_name`, ')') AS `name`, `t1`.`is_main`, `t1`.`measurement_type_metric_id`\n                        FROM `" . RefbookMeasurementTypeMetric::model()->tableName() . "` `t1`\n                        LEFT JOIN `" . RefbookMetric::model()->tableName() . "` `t2` ON `t2`.`metric_id` = `t1`.`metric_id`\n                        WHERE `t1`.`measurement_type_id` = '" . $value->measurement_type_id . "'";
             $meas_types[$key]->metrics_list = Yii::app()->db->createCommand($sql)->queryAll();
         }
     }
     if (Yii::app()->request->isPostRequest && isset($_POST['main_metric'])) {
         foreach ($_POST['main_metric'] as $key => $value) {
             if ($meas_types[$key]->metrics_list) {
                 foreach ($meas_types[$key]->metrics_list as $v1) {
                     $update = array('is_main' => $v1['metric_id'] == $value ? 1 : 0);
                     RefbookMeasurementTypeMetric::model()->updateByPk($v1['measurement_type_metric_id'], $update);
                 }
             }
         }
         StationSensorFeature::updateMetric();
         $DB = array('db' => CStubActiveRecord::getDbConnect(), 'db_long' => CStubActiveRecord::getDbConnect(true));
         foreach ($DB as $db) {
             $db->createCommand("DELETE FROM `" . ScheduleReportProcessed::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . ForwardedMessage::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . StationCalculationData::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . SeaLevelTrend::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . SensorDataMinute::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . SensorData::model()->tableName() . "`")->query();
             $db->createCommand("DELETE FROM `" . ListenerLog::model()->tableName() . "`")->query();
         }
         It::memStatus('admin_metrics_saved');
         $this->redirect($this->createUrl('admin/setup'));
     }
     $this->render('setup', array('meas_types' => $meas_types));
 }
Ejemplo n.º 18
0
 protected function listenESPTorrent($attempt = 0)
 {
     $this->_logger->log(__CLASS__ . ' ' . __METHOD__, array('attempt' => $attempt));
     $timeout = 10;
     if ($attempt == 0) {
         ListenerProcess::addComment($this->listener->listener_id, 'comment', 'trying to connect with ' . $this->source);
     } else {
         ListenerProcess::addComment($this->listener->listener_id, 'comment', 'Trying to reconnect with ' . $this->source . '; attempt #' . $attempt . '/3');
     }
     $source_parts = explode(':', $this->source);
     // creates socket connection with IP:port
     $fp = @fsockopen($source_parts[0], $source_parts[1], $errno, $errstr, $timeout);
     if ($fp !== false) {
         $attempt = 0;
         ListenerProcess::addComment($this->listener->listener_id, 'connected', 'successfully');
         $message = '';
         while (!feof($fp)) {
             $res = fwrite($fp, ' ', 2);
             //print "\n try write: ".$res;
             $line = fread($fp, 8192);
             $line = trim($line);
             $occurances_dl = strpos($line, '$');
             if ($line != '') {
                 $message .= $line;
                 if ($occurances_dl !== false) {
                     if ($this->synchronization->isMaster()) {
                         $res = ListenerLog::addNew($message, $this->listener->listener_id, $this->settings->overwrite_data_on_listening, 'datalogger');
                     } else {
                         // slave
                         //$res = ListenerLog::addNew($message, $this->listener->listener_id, $this->settings->overwrite_data_on_listening, 'datalogger');
                     }
                     ListenerProcess::addComment($this->listener->listener_id, 'comment', 'got msg #' . $res);
                     $message = '';
                 }
             }
         }
         ListenerProcess::addComment($this->listener->listener_id, 'stopped', 'can not receive data anymore - ESP is unreachable');
         fclose($fp);
     } else {
         ListenerProcess::addComment($this->listener->listener_id, 'cannot_connect', '[' . $errno . '] ' . $errstr);
     }
     if ($attempt < 3) {
         $attempt++;
         sleep(3);
     } else {
         ListenerProcess::addComment($this->listener->listener_id, 'comment', 'Three attempts to reconnect failed. Waiting for 2 minutes before trying to reconnect.');
         sleep(120);
         $attempt = 0;
     }
     return $this->listenESPTorrent($attempt);
 }
Ejemplo n.º 19
0
 public static function lastMsgIds($station_ids, &$stations = null)
 {
     $lastMessages = ListenerLog::getAllLast2Messages($station_ids);
     $lastMessageIds = array();
     foreach ($lastMessages as $key => $stationMessages) {
         //station last message
         if (isset($stations[$key])) {
             $next_expected = strtotime($stationMessages[0]->measuring_timestamp) + $stations[$key]->event_message_period * 60 + 300;
             $stations[$key]->nextMessageIsLates = $next_expected < time() ? 1 : 0;
             $stations[$key]->lastMessage = $stationMessages[0];
         }
         //log id
         foreach ($stationMessages as $message) {
             $lastMessageIds[] = $message->log_id;
         }
     }
     return $lastMessageIds;
 }
Ejemplo n.º 20
0
 public function prepareList($station_id = 0)
 {
     if ($this->hasErrors()) {
         return ['prepared_header' => [], 'prepared_data' => []];
     }
     $prepared_header = array();
     $prepared_data = array();
     $sensor_feature_code = $this->getSensorFeatureCode();
     $handler_code = array_keys($this->getSelectedGroupSensorFeatureCode());
     $search_features = array();
     $search_calcs = array();
     foreach ($sensor_feature_code as $key) {
         if (in_array($key, array_keys($this->calc_handlers))) {
             $search_calcs[] = $this->calc_handlers[$key];
         } else {
             $search_features[] = $key;
         }
     }
     if (count($this->station_id) > 1) {
         $sql_part = "`t2`.`station_id` IN (" . implode(',', $this->station_id) . ") ";
     } else {
         $sql_part = "`t2`.`station_id` = '" . $this->station_id[0] . "' ";
     }
     // 1.a) GET FEATURES
     if (count($search_features) > 0) {
         $sql = "SELECT `t1`.`sensor_feature_id`,\n                           `t1`.`feature_code`,\n                           `t1`.`sensor_id`,\n                           `t3`.`station_id_code`,\n                           `t2`.`sensor_id_code`,\n                           `t2`.`station_id`,\n                           `t4`.`handler_id_code`,\n                           `t3`.`magnetic_north_offset`\n                    FROM `" . StationSensorFeature::model()->tableName() . "` `t1`\n                    LEFT JOIN `" . StationSensor::model()->tableName() . "`   `t2` ON `t1`.`sensor_id` = `t2`.`station_sensor_id`\n                    LEFT JOIN `" . SensorDBHandler::model()->tableName() . "` `t4` ON `t4`.`handler_id` = `t2`.`handler_id`\n                    LEFT JOIN `" . Station::model()->tableName() . "`         `t3` ON `t3`.`station_id` = `t2`.`station_id`\n                    WHERE " . $sql_part . " AND `t1`.`feature_code` IN ('" . implode("','", $search_features) . "') AND `t4`.`handler_id_code` IN ('" . implode("','", $handler_code) . "')\n                    ORDER BY `t1`.`feature_code`, `t3`.`station_id_code`, `t2`.`sensor_id_code`";
         $found_sensors = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         $total_found_sensors = count($found_sensors);
     }
     // 1.b) GET CALCS
     if (count($search_calcs) > 0) {
         $sql = "SELECT `t1`.`calculation_id`,\n                           `t1`.`handler_id`,\n                           `t2`.`station_id_code`,\n                           `t2`.`station_id`,\n                           IF(`t1`.`handler_id` = 1, 'DP', 'MSL') AS `sensor_id_code`,\n                           IF(`t1`.`handler_id` = 1, 'Dew Point', 'Pressure MSL') AS `feature_code`,\n                           IF(`t1`.`handler_id` = 1, 'DewPoint', 'PressureSeaLevel') AS `handler_id_code`\n                    FROM `" . StationCalculation::model()->tableName() . "` `t1`\n                    LEFT JOIN `" . Station::model()->tableName() . "`       `t2` ON `t2`.`station_id` = `t1`.`station_id`\n                    WHERE " . $sql_part . " AND `t1`.`handler_id` IN (" . implode(',', $search_calcs) . ")\n                    ORDER BY `t1`.`handler_id`, `t2`.`station_id_code`";
         $found_calcs = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         $total_found_calcs = count($found_calcs);
     }
     $start_datetime = strtotime($this->date_from . ' ' . $this->time_from);
     $end_datetime = strtotime($this->date_to . ' ' . $this->time_to);
     $features_set = array();
     // 2.a) PREPARE HEADER
     if (is_array($found_sensors) && $total_found_sensors > 0) {
         $sensor_feature_ids = array();
         for ($i = 0; $i < $total_found_sensors; $i++) {
             $key = $found_sensors[$i]['handler_id_code'] . $found_sensors[$i]['feature_code'];
             if (!isset($prepared_header[$key])) {
                 $prepared_header[$key] = array('sensor_feature_code' => $found_sensors[$i]['feature_code'], 'handler_id_code' => $found_sensors[$i]['handler_id_code'], 'sensors' => array(), 'station_sensors' => array());
             }
             $sensor_feature_ids[] = $found_sensors[$i]['sensor_feature_id'];
             $prepared_header[$key]['sensors'][] = array('station_id' => $found_sensors[$i]['station_id'], 'sensor_id_code' => $found_sensors[$i]['sensor_id_code']);
             if (isset($prepared_header[$key]['station_sensors'][$found_sensors[$i]['station_id']])) {
                 $prepared_header[$key]['station_sensors'][$found_sensors[$i]['station_id']]++;
             } else {
                 $prepared_header[$key]['station_sensors'][$found_sensors[$i]['station_id']] = 1;
             }
             $features_set[$found_sensors[$i]['sensor_feature_id']] = array('station_id' => $found_sensors[$i]['station_id'], 'station_id_code' => $found_sensors[$i]['station_id_code'], 'value' => '-', 'sensor_id' => $found_sensors[$i]['sensor_id'], 'sensor_id_code' => $found_sensors[$i]['sensor_id_code'], 'sensor_feature_code' => $found_sensors[$i]['feature_code'], 'handler_id_code' => $found_sensors[$i]['handler_id_code'], 'magnetic_north_offset' => $found_sensors[$i]['magnetic_north_offset']);
         }
     }
     // 2.b) PREPARE HEADER
     if (count($search_calcs) > 0) {
         $sql = "SELECT `t1`.`calculation_id`,\n                           `t1`.`handler_id`,\n                           `t2`.`station_id_code`,\n                           `t2`.`station_id`,\n                           IF(`t1`.`handler_id` = 1, 'DP', 'MSL') AS `sensor_id_code`,\n                           IF(`t1`.`handler_id` = 1, 'Dew Point', 'Pressure MSL') AS `feature_code`,\n                           IF(`t1`.`handler_id` = 1, 'DewPoint', 'PressureSeaLevel') AS `handler_id_code`\n                    FROM `" . StationCalculation::model()->tableName() . "` `t1`\n                    LEFT JOIN `" . Station::model()->tableName() . "`       `t2` ON `t2`.`station_id` = `t1`.`station_id`\n                    WHERE " . $sql_part . " AND `t1`.`handler_id` IN (" . implode(',', $search_calcs) . ")\n                    ORDER BY `t1`.`handler_id`, `t2`.`station_id`";
         $found_calcs = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         if (is_array($found_calcs) && count($found_calcs) > 0) {
             $calculation_ids = array();
             for ($i = 0; $i < count($found_calcs); $i++) {
                 $key = 'calc_' . $found_calcs[$i]['handler_id'];
                 if (!isset($prepared_header[$key])) {
                     $prepared_header[$key] = array('sensor_feature_code' => $key, 'sensors' => array(), 'station_sensors' => array());
                 }
                 $calculation_ids[] = $found_calcs[$i]['calculation_id'];
                 $prepared_header[$key]['sensors'][] = array('station_id' => $found_calcs[$i]['station_id'], 'sensor_id_code' => $found_calcs[$i]['sensor_id_code']);
                 if (isset($prepared_header[$key]['station_sensors'][$found_calcs[$i]['station_id']])) {
                     $prepared_header[$key]['station_sensors'][$found_calcs[$i]['station_id']]++;
                 } else {
                     $prepared_header[$key]['station_sensors'][$found_calcs[$i]['station_id']] = 1;
                 }
                 $features_set['calc_' . $found_calcs[$i]['calculation_id']] = array('station_id' => $found_calcs[$i]['station_id'], 'station_id_code' => $found_calcs[$i]['station_id_code'], 'value' => '-', 'calculation_id' => $found_calcs[$i]['calculation_id'], 'sensor_id_code' => $found_calcs[$i]['sensor_id_code'], 'sensor_feature_code' => $found_calcs[$i]['feature_code'], 'handler_id_code' => $found_calcs[$i]['handler_id_code']);
             }
         }
     }
     // 3.a) PREPARE DATA
     if (is_array($found_sensors) && $total_found_sensors) {
         $qb = new CDbCriteria();
         $qb->select = ['sensor_data_id', 'station_id', 'sensor_id', 'sensor_feature_id', 'sensor_feature_normalized_value', 'is_m', 'measuring_timestamp'];
         $qb->addInCondition('sensor_feature_id', $sensor_feature_ids);
         $qb->addBetweenCondition('measuring_timestamp', date('Y-m-d H:i:s', $start_datetime), date('Y-m-d H:i:s', $end_datetime));
         $qb->order = 'measuring_timestamp DESC';
         $found_values = SensorData::model()->long()->findAll($qb);
         $total_found_values = count($found_values);
         if (is_array($found_values) && $total_found_values > 0) {
             if ($this->accumulation_period == 0) {
                 for ($j = 0; $j < $total_found_values; $j++) {
                     $f_id = $found_values[$j]['sensor_feature_id'];
                     $f_time = $found_values[$j]['measuring_timestamp'];
                     $f_code = $features_set[$f_id]['sensor_feature_code'];
                     $magnetic_north_offset = $features_set[$f_id]['magnetic_north_offset'];
                     $st_id = $found_values[$j]['station_id'];
                     if (!isset($prepared_data[$f_time])) {
                         $prepared_data[$f_time] = array();
                         $prepared_data[$f_time]['stations'] = array();
                     }
                     if (!isset($prepared_data[$f_time]['data'])) {
                         $prepared_data[$f_time]['data'] = $features_set;
                     }
                     $handler_obj = SensorHandler::create($features_set[$f_id]['handler_id_code']);
                     if ($found_values[$j]['is_m'] == 1) {
                         $prepared_data[$f_time]['data'][$f_id]['value'] = '-';
                     } else {
                         $found_values[$j]['sensor_feature_normalized_value'] = $handler_obj->applyOffset($found_values[$j]['sensor_feature_normalized_value'], $magnetic_north_offset);
                         $prepared_data[$f_time]['data'][$f_id]['value'] = $handler_obj->formatValue($found_values[$j]['sensor_feature_normalized_value'], $f_code);
                     }
                     if (!in_array($st_id, $prepared_data[$f_time]['stations'])) {
                         $prepared_data[$f_time]['stations'][] = $st_id;
                     }
                 }
             } else {
                 for ($j = 0; $j < $total_found_values; $j++) {
                     $f_id = $found_values[$j]['sensor_feature_id'];
                     $f_time = $found_values[$j]['measuring_timestamp'];
                     $f_code = $features_set[$f_id]['sensor_feature_code'];
                     $magnetic_north_offset = $features_set[$f_id]['magnetic_north_offset'];
                     $st_id = $found_values[$j]['station_id'];
                     $period = $start_datetime + (intval((strtotime($f_time) - $start_datetime) / ($this->accumulation_period * 60)) + 1) * $this->accumulation_period * 60;
                     $period = $period > $end_datetime ? $end_datetime : $period;
                     $period = date('Y-m-d H:i:s', $period);
                     if (!isset($prepared_data[$period])) {
                         $prepared_data[$period] = array();
                         $prepared_data[$period]['stations'] = array();
                     }
                     if (!isset($prepared_data[$period]['data'])) {
                         $prepared_data[$period]['data'] = $features_set;
                     }
                     $handler_obj = SensorHandler::create($features_set[$f_id]['handler_id_code']);
                     if ($found_values[$j]['is_m'] == 1) {
                         $prepared_data[$period]['data'][$f_id]['value'] = '-';
                     } else {
                         $found_values[$j]['sensor_feature_normalized_value'] = $handler_obj->applyOffset($found_values[$j]['sensor_feature_normalized_value'], $magnetic_north_offset);
                         $prepared_data[$period]['data'][$f_id]['value'] = ($prepared_data[$period]['data'][$f_id]['value'] ? $prepared_data[$period]['data'][$f_id]['value'] : 0) + $handler_obj->formatValue($found_values[$j]['sensor_feature_normalized_value'], $f_code);
                     }
                     if (!in_array($st_id, $prepared_data[$period]['stations'])) {
                         $prepared_data[$period]['stations'][] = $st_id;
                     }
                 }
             }
         }
     }
     // 3.b) PREPARE DATA
     if (is_array($found_calcs) && $total_found_calcs > 0) {
         $sql = "SELECT `t2`.`station_id`,\n                           `t1`.`calculation_id`,\n                           `t1`.`value`,\n                           `t2`.`measuring_timestamp`\n                    FROM `" . StationCalculationData::model()->tableName() . "` `t1`\n                    LEFT JOIN `" . ListenerLog::model()->tableName() . "` `t2` ON `t2`.`log_id` = `t1`.`listener_log_id`\n                    WHERE `t1`.`calculation_id` IN (" . implode(',', $calculation_ids) . ")\n                      AND `t2`.`measuring_timestamp` >= '" . date('Y-m-d H:i:s', $start_datetime) . "'\n                      AND `t2`.`measuring_timestamp` <= '" . date('Y-m-d H:i:s', $end_datetime) . "'\n                    ORDER BY `t2`.`measuring_timestamp` DESC";
         $found_values = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         $total_found_values = count($found_values);
         if (is_array($found_values) && $total_found_values) {
             for ($j = 0; $j < $total_found_values; $j++) {
                 $f_id = 'calc_' . $found_values[$j]['calculation_id'];
                 $f_time = $found_values[$j]['measuring_timestamp'];
                 $st_id = $found_values[$j]['station_id'];
                 if (!$prepared_data[$f_time]) {
                     $prepared_data[$f_time] = array();
                     $prepared_data[$f_time]['stations'] = array();
                 }
                 if (!$prepared_data[$f_time]['data']) {
                     $prepared_data[$f_time]['data'] = $features_set;
                 }
                 $prepared_data[$f_time]['data'][$f_id]['value'] = CalculationHandler::formatValue($found_values[$j]['value']);
                 $prepared_data[$f_time]['data'][$f_id]['station_id'] = $st_id;
                 if (!in_array($st_id, $prepared_data[$f_time]['stations'])) {
                     $prepared_data[$f_time]['stations'][] = $st_id;
                 }
             }
         }
     }
     //need sort
     krsort($prepared_data);
     //print_r(array(
     //            'prepared_header' => $prepared_header,
     //            'prepared_data' => $prepared_data,
     //        ));exit;
     return array('prepared_header' => $prepared_header, 'prepared_data' => $prepared_data);
 }
Ejemplo n.º 21
0
    public function run($args)
    {
        if (!Yii::app()->mutex->lock('ScheduleCommand', 3600)) {
            Yii::app()->end();
        }
        $synchronization = new Synchronization();
        if (!$synchronization->isMaster() and $synchronization->isProcessed()) {
            return;
        }
        $generationTime = time();
        $proper_periods = ScheduleCommand::getProperPeriods($generationTime);
        if (count($proper_periods) === 0) {
            self::$_logger->log(__METHOD__ . ' Exiting. No proper periods found.' . "\n\n");
            //            Yii::app()->mutex->unlock();
            //			Yii::app()->end();
        }
        $criteria = new CDbCriteria();
        $criteria->select = array('schedule_id', 'report_type', 'station_id', 'report_format', 'period', 'last_scheduled_run_planned', 'last_scheduled_run_fact', '(`last_scheduled_run_planned` + INTERVAL `period` MINUTE) AS nextScheduleTime', 'UNIX_TIMESTAMP(`last_scheduled_run_planned` + INTERVAL `period` MINUTE) AS nextScheduleUnixTime');
        $criteria->with = array('station');
        $criteria->compare('period', '>0');
        $criteria->compare('period', $proper_periods);
        $criteria->addCondition('(UNIX_TIMESTAMP(`last_scheduled_run_planned` + INTERVAL `period` MINUTE) <= UNIX_TIMESTAMP()
										OR
									`last_scheduled_run_planned` = "0000-00-00 00:00:00")');
        /** @var array|ScheduleReport[] $scheduledReports */
        $scheduledReports = ScheduleReport::model()->findAll($criteria);
        if (count($scheduledReports) === 0) {
            self::$_logger->log(__METHOD__ . ' Exiting. No proper reports found.' . "\n\n");
            Yii::app()->mutex->unlock();
            Yii::app()->end();
        }
        self::$_logger->log(__METHOD__ . ' New scheduled reports', array('report count' => count($scheduledReports)));
        $reportProcesses = array();
        foreach ($scheduledReports as $scheduledReport) {
            self::$_logger->log("\n");
            self::$_logger->log(__METHOD__ . ' Check scheduled report', array('schedule_id' => $scheduledReport->schedule_id));
            $check_period = ScheduleCommand::getCheckPeriod($generationTime, $scheduledReport->period);
            if ($scheduledReport->report_type === 'data_export') {
                self::$_logger->log(__METHOD__ . ' scheduledReport->report_type  = data_export');
                // add record about schedule running to process afterwards
                for ($i = 0; $i < count($scheduledReport->station); $i++) {
                    $schedule_report_process = new ScheduleReportProcessed();
                    $schedule_report_process->sr_to_s_id = $scheduledReport->station[$i]->id;
                    $schedule_report_process->check_period_start = $check_period[3];
                    $schedule_report_process->check_period_end = $check_period[4];
                    $schedule_report_process->save();
                    $scheduledReport->last_scheduled_run_fact = $check_period[1];
                    $scheduledReport->last_scheduled_run_planned = $check_period[2];
                    if ($scheduledReport->validate()) {
                        $scheduledReport->save(false);
                    } else {
                        self::$_logger->log(__METHOD__ . ' Schedule report not saved ', array('schedule_error' => $scheduledReport->getErrors()));
                    }
                    $reportProcesses[$scheduledReport->station[$i]->id] = array('schedule_id' => $scheduledReport->schedule_id, 'schedule_processed_id' => $schedule_report_process->schedule_processed_id, 'schedule_info' => $scheduledReport, 'check_period_start' => $check_period[3], 'check_period_end' => $check_period[4]);
                }
            } else {
                $logRecords = array();
                foreach ($scheduledReport->station as $station) {
                    $criteria = new CDbCriteria();
                    $criteria->compare('station_id', $station->station_id);
                    $criteria->compare('failed', '0');
                    $criteria->compare('measuring_timestamp', '>' . $check_period[0]);
                    $criteria->compare('measuring_timestamp', '<=' . $check_period[1]);
                    $criteria->order = 'measuring_timestamp desc, log_id desc';
                    $criteria->limit = '1';
                    $logRecord = ListenerLog::model()->find($criteria);
                    if (!is_null($logRecord)) {
                        $logRecords[] = $logRecord;
                    }
                }
                // add record about schedule running to process afterwards (only in case system received base message)
                if (count($logRecords) > 0) {
                    for ($i = 0; $i < count($scheduledReport->station); $i++) {
                        $schedule_report_process = new ScheduleReportProcessed();
                        $continue = false;
                        foreach ($logRecords as $logRecord) {
                            if ($logRecord->station_id == $scheduledReport->station[$i]->station_id) {
                                $schedule_report_process->listener_log_id = $logRecord->log_id;
                                $listener_log_id = $logRecord->log_id;
                                $continue = false;
                                break;
                            } else {
                                $continue = true;
                            }
                        }
                        if ($continue) {
                            continue;
                        }
                        $schedule_report_process->sr_to_s_id = $scheduledReport->station[$i]->id;
                        $schedule_report_process->check_period_start = $check_period[3];
                        $schedule_report_process->check_period_end = $check_period[4];
                        $schedule_report_process->save();
                        $scheduledReport->last_scheduled_run_fact = $check_period[1];
                        $scheduledReport->last_scheduled_run_planned = $check_period[2];
                        if ($scheduledReport->validate()) {
                            $scheduledReport->save(false);
                        } else {
                            self::$_logger->log(__METHOD__ . ' Schedule report not saved ', array('schedule_error' => $scheduledReport->getErrors()));
                        }
                        $reportProcesses[$scheduledReport->station[$i]->id] = array('log_id' => $listener_log_id, 'schedule_id' => $scheduledReport->schedule_id, 'schedule_processed_id' => $schedule_report_process->schedule_processed_id, 'schedule_info' => $scheduledReport, 'check_period_start' => $check_period[3], 'check_period_end' => $check_period[4]);
                    }
                }
            }
        }
        if (count($reportProcesses) > 0) {
            $total = count($reportProcesses);
            $i = 1;
            foreach ($reportProcesses as $reportProcess) {
                $weatherReport = null;
                switch (strtolower($reportProcess['schedule_info']->report_type)) {
                    case 'synop':
                        $weatherReport = WeatherReport::create('Synop', self::$_logger);
                        break;
                    case 'bufr':
                        $weatherReport = WeatherReport::create('Bufr', self::$_logger);
                        break;
                    case 'metar':
                        $weatherReport = WeatherReport::create('Metar', self::$_logger);
                        break;
                    case 'odss':
                        $weatherReport = WeatherReport::create('ODSS', self::$_logger);
                        break;
                    default:
                        $weatherReport = WeatherReport::create('Export', self::$_logger);
                        break;
                }
                try {
                    $weatherReport->load($reportProcess['schedule_processed_id']);
                    $weatherReport->generate();
                    $weatherReport->saveProcess();
                    $weatherReport->deliverReport();
                } catch (Exteption $e) {
                    self::$_logger->log(__METHOD__ . ' Error ', array('err' => $e->getMessage()));
                }
                self::$_logger->log(__METHOD__ . ' Completed', array('num' => $i++, 'total' => $total));
            }
        }
        //send report from sttions together
        $scheduleProcessedIdArray_schedule_id = array();
        foreach ($reportProcesses as $reportProcess) {
            $scheduleProcessedIdArray_schedule_id[$reportProcess['schedule_id']][] = $reportProcess['schedule_processed_id'];
        }
        foreach ($scheduleProcessedIdArray_schedule_id as $scheduleProcessedIdArray) {
            new WeatherReportMailSender($scheduleProcessedIdArray);
        }
        self::$_logger->log(__METHOD__ . ' Schedule report completed' . "\n\n\n\n\n\n\n\n\n");
        Yii::app()->mutex->unlock();
    }
Ejemplo n.º 22
0
 public function prepareList($page_size = 50)
 {
     $sql_where_str = $this->_prepareSqlCondition();
     $sql_order_str = $this->_prepareSqlOrder();
     if ($page_size) {
         $total = $this->total;
     }
     if ($total || !$page_size) {
         if ($page_size) {
             $pages = new CPagination($total);
             $pages->pageSize = $page_size;
         }
         $sql = "SELECT `t1`.`log_id`, `t1`.`updated`,`t1`.`measuring_timestamp`, `t1`.`created`, `t1`.`message`, `t1`.`fail_description`, t3.station_id_code, t3.display_name, t3.station_type, `t2`.`process_error_id`, `t1`.`is_processed`\n                    FROM `" . ListenerLog::model()->tableName() . "` t1\n                    LEFT JOIN `" . ListenerLogProcessError::model()->tableName() . "` `t2` ON `t2`.`log_id` = `t1`.`log_id`\n                    LEFT JOIN `" . Station::model()->tableName() . "` `t3` ON `t3`.`station_id` = `t1`.`station_id`\n                    {$sql_where_str}\n                    GROUP BY `t1`.`log_id`\n                    {$sql_order_str}";
         if ($page_size) {
             $sql .= " LIMIT " . $pages->currentPage * $pages->pageSize . ", " . $pages->pageSize;
         }
         $res = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
         if ($res) {
             $ids = array();
             foreach ($res as $key => $value) {
                 $ids[] = $value['log_id'];
                 if ($value['fail_description']) {
                     $value['errors'] = explode(',', $value['fail_description']);
                 }
                 $list[$value['log_id']] = $value;
             }
             $sql = "SELECT * FROM `" . ListenerLogProcessError::model()->tableName() . "` WHERE `log_id` IN (" . implode(',', $ids) . ")";
             $res2 = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
             if ($res2) {
                 foreach ($res2 as $key => $value) {
                     if ($value['type'] == 'error') {
                         $list[$value['log_id']]['errors'][] = $value['description'];
                     } else {
                         if ($value['type'] == 'warning') {
                             $list[$value['log_id']]['warnings'][] = $value['description'];
                         }
                     }
                 }
             }
         }
     }
     return array('list' => $list, 'pages' => $pages);
 }