Example #1
0
 protected function setHandlers()
 {
     $criteria = new CDbCriteria();
     // 1 or 2: AWS or Rain station
     $criteria->addCondition('flags & 3 > 0');
     $criteria->order = "display_name";
     $criteria->index = 'handler_id';
     $this->handlers = SensorDBHandler::model()->with('features.metric')->findAll($criteria);
     foreach ($this->handlers as $handler) {
         $this->sensor_handlers[$handler->handler_id_code] = SensorHandler::create($handler->handler_id_code);
     }
     //        echo "<pre>";
     //        print_r($this->sensor_handlers);
     //        print_r($this->handlers);
     //        echo "</pre>";
     //        exit;
 }
Example #2
0
 public function createExport()
 {
     $return_string = "";
     $sql = "SELECT\n                       `t1`.`measuring_timestamp` AS `TxDateTime`,\n                       `t4`.`station_id_code` AS `StationId`, \n                       `t4`.`display_name` AS `StationDisplayName`,\n                       `t3`.`sensor_id_code` AS `SensorId`, \n                       `t3`.`display_name` AS `SensorDisplayName`, \n                       \n                       `t1`.`period` AS `MeasurementPeriod`,\n                       `t1`.`sensor_feature_value` AS `Value`,\n                       `t5`.`short_name` AS `Metric`,\n                       `t8`.`value` AS `DewPoint`,\n                       `t11`.`value` AS `PressureMSL`,\n                       \n                       `t12`.`handler_id_code`,\n                       `t4`.`magnetic_north_offset`\n\n                 FROM `" . SensorData::model()->tableName() . "` t1\n                 LEFT JOIN `" . StationSensorFeature::model()->tableName() . "`          `t2`    ON `t2`.`sensor_feature_id` = `t1`.`sensor_feature_id`\n                 LEFT JOIN `" . StationSensor::model()->tableName() . "`                 `t3`    ON `t3`.`station_sensor_id` = `t2`.`sensor_id`\n                 LEFT JOIN `" . Station::model()->tableName() . "`                       `t4`    ON `t4`.`station_id` = `t1`.`station_id`\n                 LEFT JOIN `" . RefbookMetric::model()->tableName() . "`                 `t5`    ON `t5`.`metric_id` = `t2`.`metric_id`\n\n                 LEFT JOIN `" . StationCalculation::model()->tableName() . "`            `t6`    ON (`t6`.`station_id` = `t1`.`station_id` AND `t6`.`handler_id` = 1)\n                 LEFT JOIN `" . StationCalculationVariable::model()->tableName() . "`    `t7`    ON (`t7`.`sensor_feature_id` = `t2`.`sensor_feature_id` AND `t7`.`calculation_id` = `t6`.`calculation_id`)\n                 LEFT JOIN `" . StationCalculationData::model()->tableName() . "`        `t8`    ON (`t8`.`calculation_id` = `t7`.`calculation_id` AND `t8`.`listener_log_id` = `t1`.`listener_log_id`)\n\n                 LEFT JOIN `" . StationCalculation::model()->tableName() . "`            `t9`    ON (`t9`.`station_id` = `t1`.`station_id` AND `t9`.`handler_id` = 2)\n                 LEFT JOIN `" . StationCalculationVariable::model()->tableName() . "`    `t10`   ON (`t10`.`sensor_feature_id` = `t2`.`sensor_feature_id` AND `t10`.`calculation_id` = `t9`.`calculation_id`)\n                 LEFT JOIN `" . StationCalculationData::model()->tableName() . "`        `t11`   ON (`t11`.`calculation_id` = `t10`.`calculation_id` AND `t11`.`listener_log_id` = `t1`.`listener_log_id`)\n\n                 LEFT JOIN `" . SensorDBHandler::model()->tableName() . "`               `t12`   ON `t12`.`handler_id` = `t3`.`handler_id`\n\n                 WHERE `t1`.`station_id` IN (" . implode(',', $this->station_id) . ")\n                   AND `t1`.`measuring_timestamp` >= FROM_UNIXTIME(" . $this->start_timestamp . ") \n                   AND `t1`.`measuring_timestamp` <= FROM_UNIXTIME(" . $this->end_timestamp . ")\n                   AND `t2`.`is_main` = 1\n                   AND `t1`.`is_m` = '0'\n                 ORDER BY `t1`.`measuring_timestamp` DESC, `t4`.`station_id_code`, `t3`.`sensor_id_code`";
     $res = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
     if ($res) {
         foreach ($res as $key => $value) {
             $handler_obj = SensorHandler::create($value['handler_id_code']);
             $res[$key]['Value'] = $handler_obj->applyOffset($res[$key]['Value'], $res[$key]['magnetic_north_offset']);
             $res[$key]['Value'] = $handler_obj->formatValue($res[$key]['Value'], $res[$key]['feature_code']);
             unset($res[$key]['magnetic_north_offset']);
             unset($value['handler_id_code']);
             unset($res[$key]['feature_code']);
         }
         $return_string .= "\"AWS Stations:\"\n" . It::prepareStringCSV($res);
     }
     $sql = "SELECT\n                        `t1`.`measuring_timestamp` AS `TxDateTime`,\n                        `t3`.`station_id_code` AS `StationId`, \n                        `t3`.`display_name` AS `StationDisplayName`,\n                        `t2`.`sensor_id_code` AS `SensorId`, \n                        `t2`.`display_name` AS `SensorDisplayName`,  \n                        (`t1`.`sensor_value` * `t1`.`bucket_size`) AS `Value`,\n                        `t4`.`short_name` AS `Metric`                        \n                 FROM `" . SensorDataMinute::model()->tableName() . "` t1\n                 LEFT JOIN `" . StationSensor::model()->tableName() . "` t2 ON t2.station_sensor_id = t1.sensor_id\n                 LEFT JOIN `" . Station::model()->tableName() . "` t3 ON t3.station_id = t1.station_id\n                 LEFT JOIN `" . RefbookMetric::model()->tableName() . "` t4 ON t4.metric_id = t1.metric_id\n                     \n                 WHERE `t1`.`station_id` IN (" . implode(',', $this->station_id) . ")\n                   AND `t1`.`measuring_timestamp` >= FROM_UNIXTIME(" . $this->start_timestamp . ") \n                   AND `t1`.`measuring_timestamp` <= FROM_UNIXTIME(" . $this->end_timestamp . ")\n                   AND `t1`.`is_tmp` = 0\n                 ORDER BY t1.measuring_timestamp DESC, t3.station_id_code, t2.sensor_id_code\n                ";
     $res = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
     if ($res) {
         $return_string .= "\n\n\"RG Stations:\"\n" . It::prepareStringCSV($res);
     }
     It::downloadFile($return_string, 'export__' . date('Y-m-d_Hi') . '.csv', 'text/csv');
 }
 protected function getWindDirection()
 {
     $result = array('source_value' => null, 'value' => '///', 'description' => '');
     $sensor = isset($this->sensors['wind_direction_10']) ? $this->sensors['wind_direction_10'] : null;
     if (!is_null($sensor)) {
         if ($sensor['is_m']) {
             $result['source_value'] = 'M';
             $result['description'] = 'Last data about Wind Direction is unavailable';
         } else {
             // create object of wind direction handler
             $handler_obj = SensorHandler::create($sensor['handler_id_code'], $this->_logger);
             // apply magnetic north offset
             $value = $handler_obj->applyOffset($sensor['sensor_feature_value'], $this->station_info->magnetic_north_offset);
             $result['value'] = $this->formatWindDirection($value);
             $result['source_value'] = $sensor['sensor_feature_value'];
             $result['description'] = $result['source_value'] . ' degree';
         }
     } else {
         $result['description'] = 'No Wind Direction sensor';
     }
     $result['description'] = 'Wind Direction: <span>' . $result['value'] . '</span> => <span>' . $result['description'] . '</span>';
     return $result;
 }
 public function getInfoForAwsPanel($sensor_pairs, $sensorList, $sensorData, $for = 'panel')
 {
     $return = array();
     $sensor_ids = array();
     $sensor_measuring_time = array();
     $last_logs_ids = array();
     $last_logs_per_station = array();
     foreach ($sensor_pairs as $value) {
         $sensor_ids[] = $value['sensor_id'];
         if (count($value['last_logs']) > 0) {
             $last_logs_ids[] = $value['last_logs'][0]->log_id;
             $sensor_measuring_time[$value['sensor_id']] = $value['last_logs'][0]->measuring_timestamp;
             $last_logs_per_station[$value['station_id']][0] = $value['last_logs'][0]->log_id;
         }
         if (count($value['last_logs']) > 1) {
             $last_logs_ids[] = $value['last_logs'][1]->log_id;
             $last_logs_per_station[$value['station_id']][1] = $value['last_logs'][1]->log_id;
         }
     }
     $sensor_feature_ids = array();
     $sensor_feature_ids2 = array();
     if (isset($sensorList['humidity']) && is_array($sensorList['humidity'])) {
         foreach ($sensor_ids as $sensor_id) {
             if (!isset($sensorList['humidity'][$sensor_id])) {
                 continue;
             }
             $sensorFeature = $sensorList['humidity'][$sensor_id];
             $sensor_feature_ids[] = $sensorFeature->sensor_feature_id;
             $sensor_feature_ids2[$sensor_id] = $sensorFeature->sensor_feature_id;
             $return[$sensorFeature->sensor->station_id][$sensor_id] = array('sensor_display_name' => $sensorFeature->sensor->display_name, 'sensor_id_code' => $sensorFeature->sensor->sensor_id_code, 'metric_html_code' => is_null($sensorFeature->metric) ? '' : $sensorFeature->metric->html_code, 'group' => 'last_min24_max_24', 'last' => '-', 'period' => '-', 'max24' => '-', 'min24' => '-', 'change' => 'no', 'timezone_id' => $sensorFeature->sensor->station->timezone_id, 'filter_max' => $sensorFeature->default->filter_max, 'filter_min' => $sensorFeature->default->filter_min, 'filter_diff' => $sensorFeature->default->filter_diff, 'has_filter_max' => $sensorFeature->has_filter_max, 'has_filter_min' => $sensorFeature->has_filter_min, 'has_filter_diff' => $sensorFeature->has_filter_diff);
         }
     }
     if (count($last_logs_ids) === 0) {
         return $return;
     }
     foreach ($return as $station_id => &$sensors) {
         foreach ($sensors as $sensor_id => &$sensorValues) {
             if (isset($sensorData['humidity'][$station_id][$sensor_id]) && count($sensorData['humidity'][$station_id][$sensor_id]) > 0 && $sensorData['humidity'][$station_id][$sensor_id][0]->listener_log_id == (isset($last_logs_per_station[$station_id][0]) ? $last_logs_per_station[$station_id][0] : -1)) {
                 $sensorValue = $sensorData['humidity'][$station_id][$sensor_id][0];
                 if ($sensorValue->is_m != 1) {
                     $sensorValues['last'] = $this->formatValue($sensorValue->sensor_feature_value, 'humidity');
                     if (isset($sensorValues['has_filter_max']) && $sensorValues['has_filter_max'] == 1) {
                         if ($sensorValue->sensor_feature_value > $sensorValues['filter_max']) {
                             $sensorValues['last_filter_errors'][] = "R > " . $sensorValues['filter_max'];
                         }
                     }
                     if (isset($sensorValues['has_filter_min']) && $sensorValues['has_filter_min'] == 1) {
                         if ($sensorValue->sensor_feature_value < $sensorValues['filter_min']) {
                             $sensorValues['last_filter_errors'][] = "R < " . $sensorValues['filter_min'];
                         }
                     }
                     if (count($sensorData['humidity'][$station_id][$sensor_id]) > 3) {
                         $previousSensorValue = array();
                         for ($i = 0; $i < 4; $i++) {
                             $previousSensorValue[] = $sensorData['humidity'][$station_id][$sensor_id][$i]->sensor_feature_value;
                         }
                         if (SensorHandler::checkTrend($previousSensorValue, 1)) {
                             $sensorValues['change'] = 'up';
                         } else {
                             if (SensorHandler::checkTrend($previousSensorValue, -1)) {
                                 $sensorValues['change'] = 'down';
                             }
                         }
                         if (isset($sensorValues['has_filter_diff']) && $sensorValues['has_filter_diff'] == 1) {
                             if (abs($sensorValue->sensor_feature_value - $previousSensorValue[1]) > $sensorValues['filter_diff']) {
                                 $sensorValues['last_filter_errors'][] = "|R1 - R0| > " . $sensorValues['filter_diff'];
                             }
                         }
                     }
                 }
                 if (isset($sensor_measuring_time[$sensor_id])) {
                     $maxmin = $this->getMaxMinInDay($sensor_feature_ids2[$sensor_id], strtotime($sensor_measuring_time[$sensor_id]), 1, 0, 'humidity');
                     $sensorValues['max24'] = $maxmin['max'];
                     $sensorValues['min24'] = $maxmin['min'];
                     $sensorValues['mami_title'] = $maxmin['mami_title'];
                     $maxmin = $this->getMaxMinInDay($sensor_feature_ids2[$sensor_id], strtotime($sensor_measuring_time[$sensor_id]), 2, 0, 'humidity');
                     $sensorValues['max24_y'] = $maxmin['max'];
                     $sensorValues['min24_y'] = $maxmin['min'];
                     $sensorValues['mami_title_y'] = $maxmin['mami_title'];
                 }
             }
             foreach (array('filter_min', 'filter_max', 'filter_diff', 'has_filter_min', 'has_filter_max', 'has_filter_diff') as $unsetfield) {
                 unset($sensorValues[$unsetfield]);
             }
         }
     }
     return $return;
 }
Example #5
0
 /**
  * List sensor feature are grouped
  *
  * @return array|null $this->group_sensor_features
  */
 public function getGroupSensorsFeaturesList()
 {
     if (!$this->group_sensor_features) {
         $handlers = SensorDBHandler::getHandlers('aws');
         $rs_data = array();
         if ($handlers) {
             $measurement_codes = array();
             foreach ($handlers as $handler) {
                 $sensor_features = SensorHandler::create($handler->handler_id_code)->getAwsGraphFeatures();
                 foreach ($sensor_features as $v) {
                     if ($v['measurement_type_code']) {
                         $measurement_codes[] = $v['measurement_type_code'];
                     }
                 }
                 // get stations
                 $stations = array();
                 $station_ids = array();
                 $cssClass = "";
                 if (count($handler->sensors)) {
                     foreach ($handler->sensors as $sensor) {
                         $station = array();
                         $station['station_id_code'] = $sensor->station->station_id_code;
                         $station['station_id'] = $sensor->station->station_id;
                         $station['color'] = $sensor->station->color;
                         $stations[$station['station_id']] = $station;
                         $station_ids[$station['station_id']] = $station['station_id'];
                     }
                     $stations = array_values($stations);
                     $station_ids = array_values($station_ids);
                     $cssClass = implode('-station ', $station_ids);
                     $cssClass .= '-station ';
                     array_multisort($stations, SORT_STRING, $stations);
                 }
                 $this->group_sensor_features[$handler->handler_id_code] = ['name' => $handler->display_name, 'sensor_features' => $sensor_features, 'stations' => $stations, 'class' => $cssClass];
             }
             // Calculates
             $this->group_sensor_features['Temperature']['sensor_features']['calc_1'] = ['feature_name' => 'Dew Point, C degree'];
             $this->group_sensor_features['Pressure']['sensor_features']['calc_2'] = ['feature_name' => 'Pressure MSL, hPa'];
             // Measurement
             $sql = "SELECT `t3`.code,  `t5`.`short_name`,  `t5`.`full_name`\n                    FROM `" . RefbookMeasurementType::model()->tableName() . "`       `t3`\n                    LEFT JOIN `" . RefbookMeasurementTypeMetric::model()->tableName() . "` `t4` ON `t4`.`measurement_type_id` = `t3`.`measurement_type_id` AND `t4`.`is_main` = 1\n                    LEFT JOIN `" . RefbookMetric::model()->tableName() . "`                `t5` ON `t5`.`metric_id` = `t4`.`metric_id`\n                    WHERE `t3`.`code` IN ('" . implode("','", $measurement_codes) . "')";
             $rs = CStubActiveRecord::getDbConnect(true)->createCommand($sql)->queryAll();
             if ($rs) {
                 $rs_data = CHtml::listData($rs, 'code', 'short_name');
             }
             $wd_ws_station_params['stations'] = array();
             $wd_ws_station_params['class'] = '';
             foreach ($this->group_sensor_features as $handler_id_code => &$group) {
                 if (in_array($handler_id_code, ['WindDirection', 'WindSpeed']) && in_array('WindSpeed', array_keys($this->group_sensor_features)) && in_array('WindDirection', array_keys($this->group_sensor_features))) {
                     $station_ids_temp = array();
                     foreach ($wd_ws_station_params['stations'] as $wd_ws_station) {
                         $station_ids_temp[] = $wd_ws_station['station_id'];
                     }
                     foreach ($group['stations'] as $station) {
                         if (!in_array($station['station_id'], $station_ids_temp)) {
                             $wd_ws_station_params['stations'][] = $station;
                         }
                     }
                     $station_ids = array();
                     foreach ($wd_ws_station_params['stations'] as $wd_ws_station) {
                         $station_ids[] = $wd_ws_station['station_id'];
                     }
                     $wd_ws_station_params['class'] = implode('-station ', $station_ids) . '-station ';
                 }
                 if (in_array($handler_id_code, ['TemperatureWater', 'TemperatureSoil'])) {
                     foreach ($group['sensor_features'] as $key => $value) {
                         $group['sensor_features'][$key] = $group['name'] . ($rs_data[$value['measurement_type_code']] ? ', ' . $rs_data[$value['measurement_type_code']] : '');
                     }
                 } else {
                     foreach ($group['sensor_features'] as $key => $value) {
                         $group['sensor_features'][$key] = $value['feature_name'] . ($rs_data[$value['measurement_type_code']] ? ', ' . $rs_data[$value['measurement_type_code']] : '');
                     }
                 }
             }
         }
         /**
          * Load custom sensor feature */
         if (count($this->custom_sensor_features)) {
             $this->group_sensor_features['custom'] = ['name' => 'Custom', 'sensor_features' => $this->custom_sensor_features, 'stations' => $wd_ws_station_params['stations'], 'class' => $wd_ws_station_params['class']];
         }
     }
     return (array) $this->group_sensor_features;
 }
Example #6
0
 protected function sensorValidate($stationId, $sensorParamArray)
 {
     $handler = SensorDBHandler::model()->with('features')->findAllByAttributes(array('handler_id_code' => $sensorParamArray['handler']));
     $handler = $handler[0];
     if (!is_object($handler)) {
         $this->addError('sensor', 'handler was not found');
     }
     $sensor = new StationSensor();
     $sensor->station_id = $stationId;
     $sensor->handler_id = $handler->handler_id;
     $sensor->display_name = $sensorParamArray['display_name'];
     $sql = "SELECT UPPER(`sensor_id_code`) FROM `" . StationSensor::model()->tableName() . "` WHERE `station_id` = ? AND `sensor_id_code` <> ?";
     $used_code_id = Yii::app()->db->createCommand($sql)->queryColumn(array($stationId, $sensor->sensor_id_code ? $sensor->sensor_id_code : ''));
     for ($i = 1; $i <= 9; $i++) {
         $code = $handler->default_prefix . $i;
         if (!$used_code_id || !in_array($code, $used_code_id)) {
             $sensor->sensor_id_code = $code;
             break;
         }
     }
     if (!$sensor->sensor_id_code) {
         $this->addError('sensor', 'all numbers for sensor are busy');
     }
     $sensorHandler = SensorHandler::create($handler->handler_id_code);
     $sensorFeatures = array();
     $ft_1 = $sensorHandler->getFeatures();
     $ft_2 = $sensorHandler->getExtraFeatures();
     if ($ft_2) {
         foreach ($ft_2 as $key => $value) {
             $ft_2[$key]['is_extra'] = 1;
         }
     }
     $handler_sensor_features = array_merge($ft_1, $ft_2);
     if ($handler_sensor_features) {
         foreach ($handler_sensor_features as $value) {
             $sf = new StationSensorFeature();
             $default = $handler->features[$value['feature_code']];
             $metric = RefbookMeasurementType::model()->with('metricMain')->findByAttributes(array('code' => $value['measurement_type_code']));
             $sf->feature_constant_value = isset($value['default']) ? $value['default'] : null;
             if ($default) {
                 $sf->feature_constant_value = $default->feature_constant_value;
                 $sf->metric_id = $default->metric_id;
                 $sf->filter_max = $default->filter_max;
                 $sf->filter_min = $default->filter_min;
                 $sf->filter_diff = $default->filter_diff;
             }
             foreach ($sensorParamArray['features'] as $sensorParamFeature) {
                 if ($sensorParamFeature['feature_code'] == $value['feature_code']) {
                     $sf->feature_constant_value = $sensorParamFeature['feature_constant_value'];
                 }
             }
             $sf->metric_id = $metric->metricMain->metric_id;
             $sf->feature_code = $value['feature_code'];
             $sf->feature_display_name = $value['feature_name'];
             $sf->is_constant = isset($value['is_extra']) ? 1 : 0;
             $sf->comment = isset($value['comment']) ? $value['comment'] : null;
             $sf->measurement_type_code = $value['measurement_type_code'];
             $sf->is_cumulative = $value['is_cumulative'];
             $sf->is_main = $value['is_main'];
             $sf->has_filter_min = $value['has_filter_min'];
             $sf->has_filter_max = $value['has_filter_max'];
             $sf->has_filter_diff = $value['has_filter_diff'];
             $sensorFeatures[] = $sf;
         }
     }
     $validated = $sensor->validate();
     if ($validated) {
         $this->errors[] = $sensor->getErrors();
     }
     if ($validated and $sensorFeatures) {
         foreach ($sensorFeatures as $feature) {
             $feature->sensor_id = 1;
             if (!$feature->validate()) {
                 $this->errors[] = $feature->getErrors();
             }
         }
     }
     // sensor Save Fail
 }
 public function getInfoForAwsPanel($sensor_pairs, $sensorList, $sensorData, $for = 'panel')
 {
     $return = array();
     $sensor_ids = array();
     $sensor_measuring_time = array();
     $last_logs_ids = array();
     $last_logs_per_station = array();
     foreach ($sensor_pairs as $value) {
         $sensor_ids[] = $value['sensor_id'];
         if (count($value['last_logs']) > 0) {
             $last_logs_ids[] = $value['last_logs'][0]->log_id;
             $sensor_measuring_time[$value['sensor_id']] = $value['last_logs'][0]->measuring_timestamp;
             $last_logs_per_station[$value['station_id']][0] = $value['last_logs'][0]->log_id;
         }
         if (count($value['last_logs']) > 1) {
             $last_logs_ids[] = $value['last_logs'][1]->log_id;
             $last_logs_per_station[$value['station_id']][1] = $value['last_logs'][1]->log_id;
         }
     }
     $features = array('cloud_height_depth_1', 'cloud_height_depth_2', 'cloud_height_depth_3', 'cloud_height_height_1', 'cloud_height_height_2', 'cloud_height_height_3', 'cloud_measuring_range', 'cloud_vertical_visibility');
     $sensor_feature_ids = array();
     foreach ($features as $feature) {
         if (isset($sensorList[$feature]) && is_array($sensorList[$feature])) {
             foreach ($sensor_ids as $sensor_id) {
                 if (!isset($sensorList[$feature][$sensor_id])) {
                     continue;
                 }
                 $sensorFeature = $sensorList[$feature][$sensor_id];
                 $sensor_feature_ids[] = $sensorFeature->sensor_feature_id;
                 if (!isset($return[$sensorFeature->sensor->station_id][$sensor_id])) {
                     $return[$sensorFeature->sensor->station_id][$sensor_id] = array('sensor_display_name' => $sensorFeature->sensor->display_name, 'sensor_id_code' => $sensorFeature->sensor->sensor_id_code, 'group' => 'clouds', 'timezone_id' => $sensorFeature->sensor->station->timezone_id);
                 }
                 $return[$sensorFeature->sensor->station_id][$sensor_id][$sensorFeature->feature_code] = array('metric_html_code' => is_null($sensorFeature->metric) ? '' : $sensorFeature->metric->html_code, 'last' => '-', 'change' => 'no', 'filter_max' => $sensorFeature->default->filter_max, 'filter_min' => $sensorFeature->default->filter_min, 'filter_diff' => $sensorFeature->default->filter_diff, 'has_filter_max' => $sensorFeature->has_filter_max, 'has_filter_min' => $sensorFeature->has_filter_min, 'has_filter_diff' => $sensorFeature->has_filter_diff);
             }
         }
     }
     if (count($last_logs_ids) === 0) {
         return $return;
     }
     foreach ($features as $feature_code) {
         foreach ($return as $station_id => &$sensors) {
             foreach ($sensors as $sensor_id => &$sensorValues) {
                 if (isset($sensorData[$feature_code][$station_id][$sensor_id]) && count($sensorData[$feature_code][$station_id][$sensor_id]) > 0 && $sensorData[$feature_code][$station_id][$sensor_id][0]->listener_log_id == (isset($last_logs_per_station[$station_id][0]) ? $last_logs_per_station[$station_id][0] : -1)) {
                     $sensorValue = $sensorData[$feature_code][$station_id][$sensor_id][0];
                     if ($sensorValue->is_m != 1) {
                         $sensorValues[$feature_code]['last'] = $this->formatValue($sensorValue->sensor_feature_value, $feature_code);
                         if (isset($sensorValues[$feature_code]['has_filter_max']) && $sensorValues[$feature_code]['has_filter_max'] == 1) {
                             if ($sensorValue->sensor_feature_value > $sensorValues[$feature_code]['filter_max']) {
                                 $sensorValues[$feature_code]['last_filter_errors'][] = "R > " . $sensorValues[$feature_code]['filter_max'];
                             }
                         }
                         if (isset($sensorValues[$feature_code]['has_filter_min']) && $sensorValues[$feature_code]['has_filter_min'] == 1) {
                             if ($sensorValue->sensor_feature_value < $sensorValues[$feature_code]['filter_min']) {
                                 $sensorValues[$feature_code]['last_filter_errors'][] = "R < " . $sensorValues[$feature_code]['filter_min'];
                             }
                         }
                         if (count($sensorData[$feature_code][$station_id][$sensor_id]) > 3) {
                             $previousSensorValue = array();
                             for ($i = 0; $i < 4; $i++) {
                                 $previousSensorValue[] = $sensorData[$feature_code][$station_id][$sensor_id][$i]->sensor_feature_value;
                             }
                             if (SensorHandler::checkTrend($previousSensorValue, 1)) {
                                 $sensorValues['change'] = 'up';
                             } else {
                                 if (SensorHandler::checkTrend($previousSensorValue, -1)) {
                                     $sensorValues['change'] = 'down';
                                 }
                             }
                             if (isset($sensorValues[$feature_code]['has_filter_diff']) && $sensorValues[$feature_code]['has_filter_diff'] == 1) {
                                 if (abs($sensorValue->sensor_feature_value - $previousSensorValue[1]) > $sensorValues[$feature_code]['filter_diff']) {
                                     $sensorValues[$feature_code]['last_filter_errors'][] = "|R1 - R0| > " . $sensorValues[$feature_code]['filter_diff'];
                                 }
                             }
                         }
                     }
                 }
                 foreach (array('filter_min', 'filter_max', 'filter_diff', 'has_filter_min', 'has_filter_max', 'has_filter_diff') as $unsetfield) {
                     unset($sensorValues[$feature_code][$unsetfield]);
                 }
             }
         }
     }
     return $return;
 }
 public function __construct($logger)
 {
     $this->awsFormat = new AWSFormatConfigForm();
     parent::__construct($logger);
 }
 public function generate()
 {
     $this->_logger->log(__METHOD__);
     if ($this->errors) {
         $this->_logger->log(__METHOD__, array('errors' => $this->errors));
         return false;
     }
     $current_user_timezone = date_default_timezone_get();
     $timezone_id = 'UTC';
     if ($timezone_id != $current_user_timezone) {
         TimezoneWork::set($timezone_id);
     }
     $this->report_parts = array();
     $this->explanations = array();
     // get sensors' values for all messages received in reporting period
     $sql = "SELECT `t5`.`listener_log_id`,\r\n                       `t5`.`measuring_timestamp`,\r\n                       `t1`.`station_sensor_id`, `t1`.`sensor_id_code`, \r\n                       \r\n                       `t3`.`feature_code`, `t3`.`feature_constant_value`,\r\n                       `t4`.`code` AS `metric_code`, \r\n                       `t5`.`sensor_feature_value`, \r\n                       `t5`.`is_m`,\r\n                       `t5`.`period` AS `sensor_feature_period`,\r\n                       `t6`.`code` AS `value_metric_code`,\r\n                       `t7`.`handler_id_code`\r\n\r\n                FROM `" . SensorData::model()->tableName() . "`  `t5`\r\n                LEFT JOIN `" . StationSensor::model()->tableName() . "`        `t1` ON t1.station_sensor_id = t5.sensor_id\r\n                LEFT JOIN `" . StationSensorFeature::model()->tableName() . "` `t3` ON (`t3`.`sensor_feature_id` = `t5`.`sensor_feature_id`)\r\n                LEFT JOIN `" . RefbookMetric::model()->tableName() . "`        `t4` ON `t4`.`metric_id` = `t3`.`metric_id`\r\n                LEFT JOIN `" . RefbookMetric::model()->tableName() . "`        `t6` ON `t6`.`metric_id` = `t5`.`metric_id`\r\n                LEFT JOIN `" . SensorDBHandler::model()->tableName() . "`      `t7` ON t7.handler_id = t1.handler_id\r\n                WHERE `t5`.`station_id` = '" . $this->station_info->station_id . "' AND `t5`.`listener_log_id` IN (" . $this->schedule_process_info->listener_log_ids . ")\r\n                ORDER BY `t5`.`measuring_timestamp` DESC, `t1`.`sensor_id_code` ASC, `t3`.`feature_code` ASC";
     $sensor_data = Yii::app()->db->createCommand($sql)->queryAll();
     $data = array();
     if ($sensor_data) {
         // get calculation values for all messages received in reporting period
         $sql = "SELECT `t1`.`listener_log_id`,\r\n                           `t1`.`value`,\r\n                           `t3`.`handler_id_code`\r\n                    FROM `" . StationCalculationData::model()->tableName() . "`    `t1`\r\n                    LEFT JOIN `" . StationCalculation::model()->tableName() . "`   `t2` ON t2.calculation_id = t1.calculation_id\r\n                    LEFT JOIN `" . CalculationDBHandler::model()->tableName() . "` `t3` ON `t3`.`handler_id` = `t2`.`handler_id`\r\n                    WHERE `t2`.`station_id` = '" . $this->station_info->station_id . "' AND `t1`.`listener_log_id` IN (" . $this->schedule_process_info->listener_log_ids . ")\r\n                    ORDER BY `t3`.`handler_id_code`";
         $res2 = Yii::app()->db->createCommand($sql)->queryAll();
         if ($res2) {
             foreach ($res2 as $key => $value) {
                 $calculations[$value['listener_log_id']][] = $value;
             }
         }
         foreach ($sensor_data as $key => $value) {
             $data[$value['listener_log_id']][] = $value;
         }
         // prepare $result_item array, where each line represents line in report.
         foreach ($data as $key => $value) {
             $result_item = array('StationId', $this->station_info->station_id_code, 'WMO AWS #', $this->station_info->wmo_block_number . $this->station_info->station_number, 'National AWS #', $this->station_info->national_aws_number, 'Tx DateTime', date('m/d/Y H:i', strtotime($value[0]['measuring_timestamp'])));
             foreach ($value as $key2 => $value2) {
                 $handler_obj = SensorHandler::create($value2['handler_id_code']);
                 if (in_array($value2['handler_id_code'], array('BatteryVoltage', 'Humidity', 'Pressure', 'Temperature'))) {
                     $sensor_id_code = $value2['sensor_id_code'];
                 } else {
                     $sensor_id_code = $value2['sensor_id_code'] . ' (' . $handler_obj->getFeatureName($value2['feature_code']) . ')';
                 }
                 $result_item[] = $sensor_id_code;
                 if ($value2['is_m']) {
                     $result_item[] = '-';
                 } else {
                     $value2['sensor_feature_value'] = $handler_obj->applyOffset($value2['sensor_feature_value'], $this->station_info->magnetic_north_offset);
                     $result_item[] = str_replace(',', ' ', $handler_obj->formatValue($value2['sensor_feature_value'], $value2['feature_code']));
                 }
             }
             if (isset($calculations[$key])) {
                 foreach ($calculations[$key] as $key2 => $value2) {
                     if ($value2['handler_id_code'] === 'DewPoint') {
                         $result_item[] = 'DP';
                     } else {
                         if ($value2['handler_id_code'] === 'PressureSeaLevel') {
                             $result_item[] = 'MSL';
                         } else {
                             $result_item[] = 'Unknown calculation';
                         }
                     }
                     $result_item[] = str_replace(',', ' ', number_format(round($value2['value'], 1), 1));
                 }
             }
             $this->report_parts[] = $result_item;
         }
     }
     if ($timezone_id != $current_user_timezone) {
         TimezoneWork::set($current_user_timezone);
     }
     $this->_logger->log(__METHOD__ . ' Export generation completed.');
     return true;
 }
 public function generate()
 {
     $this->_logger->log(__METHOD__);
     $current_user_timezone = date_default_timezone_get();
     $timezone_id = 'UTC';
     if ($timezone_id != $current_user_timezone) {
         TimezoneWork::set($timezone_id);
     }
     if (is_null($this->listener_log_info)) {
         return false;
     }
     $this->_logger->log(__METHOD__ . "this->listener_log_info->log_id " . $this->listener_log_info->log_id);
     $this->sensors = $this->prepareSensorsInfo($this->listener_log_info->log_id);
     $this->calculations = $this->_prepareCalculationsInfo($this->listener_log_info->log_id);
     if ($timezone_id != $current_user_timezone) {
         TimezoneWork::set($current_user_timezone);
     }
     if ($this->errors) {
         $this->_logger->log(__METHOD__, array('errors' => $this->errors));
         return false;
     }
     $this->report_parts = array();
     $this->explanations = array();
     $measuring_timestamp = strtotime($this->listener_log_info->measuring_timestamp);
     $measuring_day = gmdate('d', $measuring_timestamp);
     $measuring_hour = gmdate('H', $measuring_timestamp);
     $measuring_minute = gmdate('i', $measuring_timestamp);
     $section = 0;
     $i = 0;
     // Section #0 - #0
     // CONSTANT
     $this->report_parts[$section][$i] = 'AAXX';
     $this->explanations[$section][$i][] = '<span>AAXX</span>: Fixed';
     $i++;
     $this->explanations[$section][$i][] = ' ';
     // Section #0 - #1
     // Day of the month (UTC), with 01 indicating the first day, 02 the second day,
     // etc.: @DTKY01111229 => 29
     $this->report_parts[$section][$i] = $measuring_day;
     $this->explanations[$section][$i][] = "<span>" . $this->report_parts[$section][$i] . "</span>: Day of the month. Measurement timestamp = '" . $this->listener_log_info->measuring_timestamp . " UTC'";
     // Section #0 - #2
     // Actual time of observation, to the nearest whole hour UTC (Barometer reading time)
     // (round up or down to nearest hour):
     // @DTKY011112290653 => 0653 => 07
     $this->report_parts[$section][$i] .= $measuring_minute >= 30 ? $measuring_hour + 1 : $measuring_hour;
     $this->explanations[$section][$i][] = "<span>" . $measuring_hour . "</span>: Actual time of observation, to the nearest whole hour UTC." . ($measuring_minute >= 30 ? ' +1 = ' . ($measuring_hour + 1) . '. Because minutes >= 30' : '');
     // Section #0 - #3
     // Indicator for source and units of wind speed (1 = m/s) => taken from table 1855
     if (isset($this->sensors['wind_speed_10'])) {
         if ($this->sensors['wind_speed_10']['metric_code'] === 'meter_per_second') {
             $this->report_parts[$section][$i] .= '1';
             $this->explanations[$section][$i][] = "<span>1</span>: Indicator for source and units of wind speed. Sensor " . $this->sensors['wind_speed_10']['sensor_id_code'] . " metric is 'meter_per_second' (see table 1855)";
         } else {
             if ($this->sensors['wind_speed_10']['metric_code'] === 'knot') {
                 $this->report_parts[$section][$i] .= '4';
                 $this->explanations[$section][$i][] = "<span>4</span>: Indicator for source and units of wind speed. Sensor " . $this->sensors['wind_speed_10']['sensor_id_code'] . " metric is 'knot' (see table 1855)";
             } else {
                 $this->report_parts[$section][$i] .= '/';
                 $this->explanations[$section][$i][] = "<span>/</span>: Indicator for source and units of wind speed. Sensor " . $this->sensors['wind_speed_10']['sensor_id_code'] . " metric is '" . $this->sensors['wind_speed_10']['metric_code'] . "' wich has not association in Table 1855";
             }
         }
     } else {
         $this->report_parts[$section][$i] .= '/';
         $this->explanations[$section][$i][] = "<span>/</span>: Indicator for source and units of wind speed. Station has not Wind Speed sensor";
     }
     $i++;
     $this->explanations[$section][$i][] = ' ';
     // Section #0 - #4
     // WMO Block# (take from the station setup) => admin > stations > tky01 = 08 (make sure to add the 0's)
     $this->report_parts[$section][$i] = str_pad($this->station_info['wmo_block_number'], 2, '0', STR_PAD_LEFT);
     $this->explanations[$section][$i][] = '<span>' . $this->station_info['wmo_block_number'] . '</span>: WMO Block#.';
     // Section #0 - #5
     // WMO Station # (take from the station setup) => admin > stations > tky01 = 007
     $this->report_parts[$section][$i] .= str_pad($this->station_info['station_number'], 3, '0', STR_PAD_LEFT);
     $this->explanations[$section][$i][] = '<span>' . $this->station_info['station_number'] . '</span>: WMO Station#.';
     $i++;
     $section = 1;
     // SECTION #1
     // Section #1 - #0
     // Indicator for inclusion or omission of precipitation data (Table 1819):
     // RN1038003018114366: there was rain, we only include in section 1
     $this->report_parts[$section][$i] = isset($this->sensors['rain_in_period']) ? '1' : '0';
     $this->explanations[$section][$i][] = "<span>" . (isset($this->sensors['rain_in_period']) ? '1' : '0') . "</span>: Indicator for RAIN inclusion. The station has rain sensor " . $this->sensors['rain_in_period']['sensor_id_code'];
     // Section #1 - #1
     // Indicator for type of station operation (manned or automatic) and for present and past weather data (1860):
     // 6 (if automatic) or 3 (if manned)..
     $this->report_parts[$section][$i] .= '6';
     $this->explanations[$section][$i][] = "<span>6</span>: Automatic station. Because all stations in this software are automatic.";
     // If Cloud Amount Height is present then take it, otherwise - Cloud Depth Height
     $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);
     // Section #1 - #2
     // Height above surface of the base of the lowest cloud seen
     if (!is_null($cloudHeightSensor)) {
         if ($cloudHeightSensor['is_m'] == 1) {
             $this->report_parts[$section][$i] .= '/';
             $this->explanations[$section][$i][] = "<span>/</span>: Height above surface of the base of the lowest cloud seen. Because Cloud Sensor height#1 value is unavailable";
         } else {
             $tmp_data = It::convertMetric($cloudHeightSensor['sensor_feature_value'], $cloudHeightSensor['metric_code'], 'meter');
             $tmp_data2 = $this->_get_cloud_height_code($tmp_data);
             $this->report_parts[$section][$i] .= $tmp_data2;
             $this->explanations[$section][$i][] = "<span>" . $tmp_data2 . "</span>: Height above surface of the base of the lowest cloud seen. (Cloud Height #1 = " . round($cloudHeightSensor['sensor_feature_value'], 1) . " " . $cloudHeightSensor['metric_code'] . " = " . round($tmp_data, 1) . " meter, see table 1600.)";
         }
     } else {
         $this->report_parts[$section][$i] .= '/';
         $this->explanations[$section][$i][] = "<span>/</span>: Height above surface of the base of the lowest cloud seen. Because no Cloud Sensor";
     }
     // Section #1 - #3
     // Horizontal visibility at surface
     if (isset($this->sensors['visibility_1'])) {
         if ($this->sensors['visibility_1']['is_m']) {
             $this->report_parts[$section][$i] .= '//';
             $this->explanations[$section][$i][] = "<span>//</span>: Horizontal visibility at surface. Because value of Visibility Sensor is unavailable.";
         } else {
             $tmp_data = It::convertMetric($this->sensors['visibility_1']['sensor_feature_value'], $this->sensors['visibility_1']['metric_code'], 'kilometer');
             $tmp_data2 = $this->_get_visibility_code($tmp_data);
             $this->report_parts[$section][$i] .= $tmp_data2;
             $this->explanations[$section][$i][] = "<span>" . $tmp_data2 . "</span>: Horizontal visibility at surface. (Visibility = " . round($this->sensors['visibility_1']['sensor_feature_value'], 1) . " " . $this->sensors['visibility_1']['metric_code'] . " = " . round($tmp_data, 1) . " km, See table 4377) ";
         }
     } else {
         $this->report_parts[$section][$i] .= '//';
         $this->explanations[$section][$i][] = "<span>//</span>: Horizontal visibility at surface. Because no Visibility Sensor";
     }
     $i++;
     $this->explanations[$section][$i][] = ' ';
     // Section #1 - #4
     // Cloud cover (2700)
     if (isset($this->sensors['cloud_amount_amount_total'])) {
         if ($this->sensors['cloud_amount_amount_total']['is_m']) {
             $this->report_parts[$section][$i] = '/';
             $this->explanations[$section][$i][] = "<span>/</span>: Cloud cover. Because value of Cloud Sensor is unavailable";
         } else {
             $tmp_data = $this->_get_cloud_cover_code(round($this->sensors['cloud_amount_amount_total']['sensor_feature_value'], 1));
             $this->report_parts[$section][$i] = $tmp_data;
             $this->explanations[$section][$i][] = "<span>" . $tmp_data . "</span>: Cloud cover. (Cloud Amount #1 = " . round($this->sensors['cloud_amount_amount_total']['sensor_feature_value']) . "/8. See code table 2700)";
         }
     } else {
         $this->report_parts[$section][$i] = '/';
         $this->explanations[$section][$i][] = "<span>/</span>: Cloud cover. Because no info about Cloud Amount";
     }
     // Section #1 - #5
     // True Wind Direction (Table 0877)
     // Example: WD11245 => 245 degrees => table 0877 => 25
     if (isset($this->sensors['wind_direction_10'])) {
         if ($this->sensors['wind_direction_10']['is_m']) {
             $this->report_parts[$section][$i] .= '//';
             $this->explanations[$section][$i][] = "<span>//</span>: True Wind Direction. Because value of Wind Direction sensor is unavailable.";
         } else {
             $handler_obj = SensorHandler::create($this->sensors['wind_direction_10']['handler_id_code']);
             $value = $handler_obj->applyOffset($this->sensors['wind_direction_10']['sensor_feature_value'], $this->station_info['magnetic_north_offset']);
             $value = It::convertMetric($value, $this->sensors['wind_direction_10']['metric_code'], 'degree');
             $tmp_val = $this->_get_wind_direction_code($value);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: True Wind Direction. Because value of " . $this->sensors['wind_direction_10']['sensor_id_code'] . ' = ' . $value . ' degree. See table 0877.';
         }
     } else {
         $this->report_parts[$section][$i] .= '//';
         $this->explanations[$section][$i][] = "<span>//</span>: True Wind Direction. Because no Wind Direction sensor";
     }
     // Section #1 - #6
     // Wind Speed in Units (rounded meter per second )
     // Example: WS23069006540632 => instantaneous = 0690
     if (isset($this->sensors['wind_speed_10'])) {
         if ($this->sensors['wind_speed_10']['is_m']) {
             $this->report_parts[$section][$i] .= '//';
             $this->explanations[$section][$i][] = "<span>//</span>: Because value of Wind Speed sensor is unavailable.";
         } else {
             $value = It::convertMetric($this->sensors['wind_speed_10']['sensor_feature_value'], $this->sensors['wind_speed_10']['metric_code'], 'meter_per_second');
             $tmp_val = round($value);
             $tmp_val = substr($tmp_val, -2);
             $tmp_val = str_pad($tmp_val, 2, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span> m/s: Wind Speed in Units. Because value of " . $this->sensors['wind_speed_10']['sensor_id_code'] . " = " . $this->sensors['wind_speed_10']['sensor_feature_value'] . " " . $this->sensors['wind_speed_10']['metric_code'];
         }
     } else {
         $this->report_parts[$section][$i] .= '//';
         $this->explanations[$section][$i][] = "<span>//</span>: Wind Speed in Units. Because no Wind Speed sensor.";
     }
     $i++;
     $this->explanations[$section][$i][] = ' ';
     // Section #1 - #7
     // FIXED
     $this->report_parts[$section][$i] = '1';
     $this->explanations[$section][$i][] = '<span>1</span>: Fixed.';
     // Section #1 - #8 - Sign of the data (Code table 3845), in this case relative to temperature (Celsius): TP11772
     // Section #1 - #9 - Air temperature, in tenths of a degree Celsius (observed): TP11772
     if (isset($this->sensors['temperature'])) {
         if ($this->sensors['temperature']['is_m']) {
             $this->report_parts[$section][$i] .= '/';
             $this->explanations[$section][$i][] = "<span>/</span>: Sign of the temperature data (Celsius). Because value of Temperature Sensor is unavailable.";
             $this->report_parts[$section][$i] .= '///';
             $this->explanations[$section][$i][] = "<span>///</span>: Air temperature, in tenths of a degree Celsius. Because value Temperature Sensor is unavailable.";
         } else {
             $value = It::convertMetric($this->sensors['temperature']['sensor_feature_value'], $this->sensors['temperature']['metric_code'], 'celsius');
             $tmp_val = $value >= 0 ? '0' : '1';
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Sign of the temperature data (Celsius). Because value of " . $this->sensors['temperature']['sensor_id_code'] . " = " . $value . " Celsius degree" . ($this->sensors['temperature']['metric_code'] != 'celsius' ? ' (' . $this->sensors['temperature']['sensor_feature_value'] . ' ' . $this->sensors['temperature']['metric_code'] . ')' : '') . ". See table 3845.";
             $tmp_val = abs(round($value * 10));
             $tmp_val = substr($tmp_val, -3);
             $tmp_val = str_pad($tmp_val, 3, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Air temperature, in tenths of a degree Celsius. Because value of " . $this->sensors['temperature']['sensor_id_code'] . " = " . $value . " Celsius degree" . ($this->sensors['temperature']['metric_code'] != 'celsius' ? ' (' . $this->sensors['temperature']['sensor_feature_value'] . ' ' . $this->sensors['temperature']['metric_code'] . ')' : '') . "";
         }
     } else {
         $this->report_parts[$section][$i] .= '/';
         $this->explanations[$section][$i][] = "<span>/</span>: Sign of the temperature data (Celsius). Because no Temperature Sensor.";
         $this->report_parts[$section][$i] .= '///';
         $this->explanations[$section][$i][] = "<span>///</span>: Air temperature, in tenths of a degree Celsius. Because no Temperature Sensor.";
     }
     $i++;
     $this->explanations[$section][$i][] = " ";
     // Section #1 - #10 FIXED
     $this->report_parts[$section][$i] = '2';
     $this->explanations[$section][$i][] = "<span>2</span>: Fixed.";
     // Section #1 - #11 - Sign of the data (Code table 3845), in this case relative to DewPoint or Humidity (if there is now DewPoint)
     // Section #1 - #12 - Dew Point (include if calculated), else Humidity (HU in case sn =9) (observed) => no DewPoint or Humidity.. Can we exclude it? Have to add '///'? Can we exclude 'Sn' as well?
     if (isset($this->calculations['DewPoint'])) {
         $tmp_val = $this->calculations['DewPoint']['value'] >= 0 ? '0' : '1';
         $this->report_parts[$section][$i] .= $tmp_val;
         $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Sign of the data (Code table 3845), in this case relative to DewPoint or Humidity (if there is no DewPoint). Because 1) we have DewPoint; 2) DewPoint value is = " . $this->calculations['DewPoint']['value'];
         $tmp_val = round(abs($this->calculations['DewPoint']['value'] * 10));
         $tmp_val = substr($tmp_val, -3);
         $tmp_val = str_pad($tmp_val, 3, '0', STR_PAD_LEFT);
         $this->report_parts[$section][$i] .= $tmp_val;
         $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Dew Point (include if calculated), else Humidity (HU in case sn=9). Because we have Dew Point calculation and its vaue = " . $this->calculations['DewPoint']['value'];
     } else {
         if (isset($this->sensors['humidity']) && !$this->sensors['humidity']['is_m']) {
             $this->report_parts[$section][$i] .= '9';
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Sign of the data (Code table 3845), in this case relative to DewPoint or Humidity (if there is no DewPoint). Because 1) we have don't have DewPoint, but we have Humidity; 2) result is 9 according to table 3845.";
             $tmp_val = round($this->sensors['humidity']['sensor_feature_value']);
             $tmp_val = substr($tmp_val, -3);
             $tmp_val = str_pad($tmp_val, 3, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Dew Point (include if calculated), else Humidity (HU in case sn=9). Because we don't have DewPoint calculation, but we have Humidity Sensor " . $this->sensors['humidity']['sensor_id_code'] . ' with value = ' . $this->sensors['humidity']['sensor_feature_value'] . '%';
         } else {
             $this->report_parts[$section][$i] .= '/';
             $this->explanations[$section][$i][] = "<span>/</span>: Sign of the data (Code table 3845), in this case relative to DewPoint or Humidity (if there is no DewPoint). Because Station has not DewPoint Calculation, Humidity Sensor";
             $this->report_parts[$section][$i] .= '///';
             $this->explanations[$section][$i][] = "<span>///</span>: Dew Point (include if calculated), else Humidity (HU in case sn=9). Because Station has not DewPoint Calculation, Humidity Sensor";
         }
     }
     $i++;
     $this->explanations[$section][$i][] = " ";
     // Section #1 - #13
     // FIXED
     $this->report_parts[$section][$i] = '3';
     $this->explanations[$section][$i][] = "<span>3</span>: Fixed.";
     // Section #1 - #14
     // Pressure at station level, in tenths of a hectopascal, omitting thousands
     // digit of hectopascals of the pressure value. (observed)
     // Example: PR105090
     if (isset($this->sensors['pressure'])) {
         if ($this->sensors['pressure']['is_m']) {
             $this->report_parts[$section][$i] .= '////';
             $this->explanations[$section][$i][] = "<span>////</span>: Pressure at station level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. Because value of Pressure Sensor is unavailable.";
         } else {
             $value = It::convertMetric($this->sensors['pressure']['sensor_feature_value'], $this->sensors['pressure']['metric_code'], 'hpascal');
             $tmp_val = round($value * 10);
             $tmp_val = substr($tmp_val, -4);
             $tmp_val = str_pad($tmp_val, 4, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Pressure at station level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. Because value of Pressure Sensor " . $this->sensors['pressure']['sensor_id_code'] . ' = ' . $this->sensors['pressure']['sensor_feature_value'] . ' ' . $this->sensors['pressure']['metric_code'] . ($this->sensors['pressure']['metric_code'] != 'hpascal' ? ' (' . $value . ' hPa)' : '');
         }
     } else {
         $this->report_parts[$section][$i] .= '////';
         $this->explanations[$section][$i][] = "<span>////</span>: Pressure at station level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. Because no Pressure Sensor.";
     }
     $i++;
     $this->explanations[$section][$i][] = " ";
     // Section #1 - #15 FIXED
     $this->report_parts[$section][$i] = '4';
     $this->explanations[$section][$i][] = "<span>4</span>: Fixed.";
     // Section #1 - #16 - Pressure at mean sea level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. (assuming accurate adjustment to sea level in possible) (Calculated)
     if (isset($this->calculations['PressureSeaLevel'])) {
         $tmp_val = round(abs($this->calculations['PressureSeaLevel']['value'] * 10));
         $tmp_val = substr($tmp_val, -4);
         $tmp_val = str_pad($tmp_val, 4, '0', STR_PAD_LEFT);
         $this->report_parts[$section][$i] .= $tmp_val;
         $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Pressure at mean sea level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. Because Pressure MSL=" . $this->calculations['PressureSeaLevel']['value'];
     } else {
         $this->report_parts[$section][$i] .= '////';
         $this->explanations[$section][$i][] = "<span>////</span>: Pressure at mean sea level, in tenths of a hectopascal, omitting thousands digit of hectopascals of the pressure value. Because no calculation Pressure MSL";
     }
     $i++;
     $this->explanations[$section][$i][] = " ";
     // Section #1 - #17 - FIXED
     $this->report_parts[$section][$i] = '6';
     $this->explanations[$section][$i][] = "<span>6</span>: Fixed.";
     // Section #1 - #18
     // Amount of precipitation which has fallen during the period preceding the time of observation, as indicated by tR (Table 3590)
     if (isset($this->sensors['rain_in_period'])) {
         if ($this->sensors['rain_in_period']['is_m']) {
             $this->report_parts[$section][$i] .= '///';
             $this->explanations[$section][$i][] = '<span>///</span>: Amount of precipitation which has fallen during the period preceding the time of observation. Because value of Rain Sensor is unavailable.';
         } else {
             $value = It::convertMetric($this->sensors['rain_in_period']['sensor_feature_value'], $this->sensors['rain_in_period']['metric_code'], 'millimeter');
             $tmp_val = $this->_get_rain_code($value);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Amount of precipitation which has fallen during the period preceding the time of observation. Because value of Rain Sensor " . $this->sensors['rain_in_period']['sensor_id_code'] . " = " . $this->sensors['rain_in_period']['sensor_feature_value'] . ' ' . $this->sensors['rain_in_period']['metric_code'] . ', see table 3590 to understand result.';
         }
     } else {
         $this->report_parts[$section][$i] .= '///';
         $this->explanations[$section][$i][] = '<span>///</span>: Amount of precipitation which has fallen during the period preceding the time of observation. Because no Rain sensor';
     }
     // Section #1 - #19
     // Duration of period of reference for amount of precipitation (Table 4019);
     // This depends upon the period of transmission of SYNOP. If hourly transmission then the data should be for 1 hour.
     $tmp_val = $this->_get_duration_of_synop_transmission($this->schedule_info->period);
     $this->report_parts[$section][$i] .= $tmp_val;
     $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Duration of period of reference for amount of precipitation. Because period of SYNOP transmission is " . $this->schedule_info->period . ' minutes, see table 4019 to understand result';
     $i++;
     // Section #2 is not included
     // Section #3 - #20 - FIXED
     $section = 3;
     $this->report_parts[$section][$i] = '333';
     $this->explanations[$section][$i][] = '<span>333</span>: Fixed.';
     $i++;
     $this->explanations[$section][$i][] = " ";
     $this->report_parts[$section][$i] = '5';
     $this->explanations[$section][$i][] = "<span>5</span>: Fixed.";
     //$i++;
     if ((!isset($this->sensors['solar_radiation_in_period']) || $this->sensors['solar_radiation_in_period']['is_m']) && (!isset($this->sensors['sun_duration_in_period']) || $this->sensors['sun_duration_in_period']['is_m'])) {
         $this->report_parts[$section][$i] = '/////////';
         $this->explanations[$section][$i][] = "<span>/////////</span>: No Solar Radiation, no Sun Duration sensor.";
     } else {
         $this->report_parts[$section][$i] = '53';
         $this->explanations[$section][$i][] = "<span>53</span>: Is fixed.";
         if (isset($this->sensors['solar_radiation_in_period'])) {
             $tmp_val = ceil($this->sensors['solar_radiation_in_period']['sensor_feature_period'] / 6);
             $tmp_val = substr($tmp_val, -2);
             $tmp_val = str_pad($tmp_val, 2, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Duration of period for Solar Radiation " . $this->sensors['solar_radiation_in_period']['sensor_id_code'] . " (" . $this->sensors['solar_radiation_in_period']['sensor_feature_period'] . " / 6). Highest whole figure was taken.";
             $this->report_parts[$section][$i] .= '2';
             $this->explanations[$section][$i][] = "<span>2</span>: Fixed and = 2, because period of Solar Radiation " . $this->sensors['solar_radiation_in_period']['sensor_id_code'] . " was taken (Not period of Sun Duration). Period for Solar Radiation (" . $this->sensors['solar_radiation_in_period']['sensor_feature_period'] . " / 6). Highest whole figure was taken.";
             $value = It::convertMetric($this->sensors['solar_radiation_in_period']['sensor_feature_value'], $this->sensors['solar_radiation_in_period']['metric_code'], 'kjoule_per_sq_meter');
             $tmp_val = substr(round($value), -4);
             $tmp_val = str_pad($tmp_val, 4, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Value of Solar Radiation Sensor " . $this->sensors['solar_radiation_in_period']['sensor_id_code'] . " = " . $this->sensors['solar_radiation_in_period']['sensor_feature_value'] . ' ' . $this->sensors['solar_radiation_in_period']['metric_code'] . ($this->sensors['solar_radiation_in_period']['metric_code'] != 'kjoule_per_sq_meter' ? ' ( = ' . $value . ' kjoule_per_sq_meter)' : '');
         } else {
             $tmp_val = ceil($this->sensors['sun_duration_in_period']['sensor_feature_period'] / 6);
             $tmp_val = substr($tmp_val, -2);
             $tmp_val = str_pad($tmp_val, 2, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Duration of period for Sun Duration " . $this->sensors['sun_duration_in_period']['sensor_id_code'] . " measurememt (" . $this->sensors['sun_duration_in_period']['sensor_feature_period'] . " / 6). Highest whole figure was taken.";
             $this->report_parts[$section][$i] .= '3';
             $this->explanations[$section][$i][] = "<span>3</span>: Fixed and = 3, because period of Sun Duration " . $this->sensors['sun_duration_in_period']['sensor_id_code'] . " was taken (Not period of Solar Radiation). Period for Sun Duration (" . $this->sensors['sun_duration_in_period']['sensor_feature_period'] . " / 6). Highest whole figure was taken.";
             $tmp_val = round($this->sensors['sun_duration_in_period']['sensor_feature_value']);
             $tmp_val = substr($tmp_val, -4);
             $tmp_val = str_pad($tmp_val, 4, '0', STR_PAD_LEFT);
             $this->report_parts[$section][$i] .= $tmp_val;
             $this->explanations[$section][$i][] = "<span>" . $tmp_val . "</span>: Value of Sun Duration Sensor " . $this->sensors['sun_duration_in_period']['sensor_id_code'] . " = " . $this->sensors['sun_duration_in_period']['sensor_feature_value'] . ' ' . $this->sensors['sun_duration_in_period']['metric_code'] . ' minutes';
         }
     }
     return true;
 }
 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);
 }
 public function getInfoForAwsPanel($sensor_pairs, $sensorList, $sensorData, $for = 'panel')
 {
     $return = array();
     $sensor_ids = array();
     $sensor_measuring_time = array();
     $last_logs_ids = array();
     $last_logs_per_station = array();
     $first_logs_ids = array();
     foreach ($sensor_pairs as $value) {
         $sensor_ids[] = $value['sensor_id'];
         if (count($value['last_logs']) > 0) {
             $first_logs_ids[] = $value['last_logs'][0]->log_id;
             $last_logs_ids[] = $value['last_logs'][0]->log_id;
             $sensor_measuring_time[$value['sensor_id']] = $value['last_logs'][0]->measuring_timestamp;
             $last_logs_per_station[$value['station_id']][0] = $value['last_logs'][0]->log_id;
         }
         if (count($value['last_logs']) > 1) {
             $last_logs_ids[] = $value['last_logs'][1]->log_id;
             $last_logs_per_station[$value['station_id']][1] = $value['last_logs'][1]->log_id;
         }
     }
     $sensor_feature_ids = array();
     $sensor_feature_ids2 = array();
     if (isset($sensorList['wind_speed_1']) && is_array($sensorList['wind_speed_1'])) {
         foreach ($sensor_ids as $sensor_id) {
             if (!isset($sensorList['wind_speed_1'][$sensor_id])) {
                 continue;
             }
             $sensorFeature = $sensorList['wind_speed_1'][$sensor_id];
             $sensor_feature_ids[] = $sensorFeature->sensor_feature_id;
             $sensor_feature_ids2[$sensor_id] = $sensorFeature->sensor_feature_id;
             $return[$sensorFeature->sensor->station_id][$sensor_id] = array('sensor_display_name' => $sensorFeature->sensor->display_name, 'sensor_id_code' => $sensorFeature->sensor->sensor_id_code, 'metric_html_code' => is_null($sensorFeature->metric) ? '' : $sensorFeature->metric->html_code, 'group' => 'last_min24_max_24', 'last' => '-', '2minute_average' => '-', '10minute_average' => '-', 'max24' => '-', 'min24' => '-', 'average' => '-', 'change' => 'no', 'timezone_id' => $sensorFeature->sensor->station->timezone_id, 'filter_max' => $sensorFeature->default->filter_max, 'filter_min' => $sensorFeature->default->filter_min, 'filter_diff' => $sensorFeature->default->filter_diff);
         }
     }
     if (count($last_logs_ids) === 0) {
         return $return;
     }
     $windAverages = array('wind_speed_2' => '2minute_average', 'wind_speed_10' => '10minute_average');
     foreach ($return as $station_id => &$sensors) {
         foreach ($sensors as $sensor_id => &$sensorValues) {
             if (isset($sensorData['wind_speed_1'][$station_id][$sensor_id]) && count($sensorData['wind_speed_1'][$station_id][$sensor_id]) > 0 && $sensorData['wind_speed_1'][$station_id][$sensor_id][0]->listener_log_id == (isset($last_logs_per_station[$station_id][0]) ? $last_logs_per_station[$station_id][0] : -1)) {
                 $sensorValue = $sensorData['wind_speed_1'][$station_id][$sensor_id][0];
                 if ($sensorValue->is_m != 1) {
                     $sensorValues['last'] = $this->formatValue($sensorValue->sensor_feature_value, 'wind_speed_1');
                     if (isset($sensorValues['has_filter_max']) && $sensorValues['has_filter_max'] == 1) {
                         if ($sensorValue->sensor_feature_value > $sensorValues['filter_max']) {
                             $sensorValues['last_filter_errors'][] = "R > " . $sensorValues['filter_max'];
                         }
                     }
                     if (isset($sensorValues['has_filter_min']) && $sensorValues['has_filter_min'] == 1) {
                         if ($sensorValue->sensor_feature_value < $sensorValues['filter_min']) {
                             $sensorValues['last_filter_errors'][] = "R < " . $sensorValues['filter_min'];
                         }
                     }
                     if (count($sensorData['wind_speed_1'][$station_id][$sensor_id]) > 3) {
                         $previousSensorValue = array();
                         for ($i = 0; $i < 4; $i++) {
                             $previousSensorValue[] = $sensorData['wind_speed_1'][$station_id][$sensor_id][$i]->sensor_feature_value;
                         }
                         if (SensorHandler::checkTrend($previousSensorValue, 1)) {
                             $sensorValues['change'] = 'up';
                         } else {
                             if (SensorHandler::checkTrend($previousSensorValue, -1)) {
                                 $sensorValues['change'] = 'down';
                             }
                         }
                         if (isset($sensorValues['has_filter_diff']) && $sensorValues['has_filter_diff'] == 1) {
                             if (abs($sensorValue->sensor_feature_value - $previousSensorValue[1]) > $sensorValues['filter_diff']) {
                                 $sensorValues['last_filter_errors'][] = "|R1 - R0| > " . $sensorValues['filter_diff'];
                             }
                         }
                     }
                 }
                 if (isset($sensor_measuring_time[$sensor_id])) {
                     $maxmin = $this->getMaxMinInDay($sensor_feature_ids2[$sensor_id], strtotime($sensor_measuring_time[$sensor_id]), 1, 0, 'wind_speed_1');
                     $sensorValues['max24'] = $maxmin['max'];
                     $sensorValues['min24'] = $maxmin['min'];
                     $sensorValues['mami_title'] = $maxmin['mami_title'];
                     if ($maxmin['max'] != '-' && $maxmin['min'] != '-') {
                         $sensorValues['average'] = $this->formatValue(($maxmin['max'] + $maxmin['min']) / 2, 'wind_speed_1');
                     } else {
                         if ($maxmin['max'] != '-') {
                             $sensorValues['average'] = $this->formatValue($maxmin['max'], 'wind_speed_1');
                         } else {
                             if ($maxmin['min'] != '-') {
                                 $sensorValues['average'] = $this->formatValue($maxmin['min'], 'wind_speed_1');
                             }
                         }
                     }
                     $maxmin_y = $this->getMaxMinInDay($sensor_feature_ids2[$sensor_id], strtotime($sensor_measuring_time[$sensor_id]), 2, 0, 'wind_speed_1');
                     $sensorValues['max24_y'] = $maxmin_y['max'];
                     $sensorValues['min24_y'] = $maxmin_y['min'];
                     $sensorValues['mami_title_y'] = $maxmin_y['mami_title'];
                     if ($maxmin_y['max'] != '-' && $maxmin_y['min'] != '-') {
                         $sensorValues['average_y'] = $this->formatValue(($maxmin_y['max'] + $maxmin_y['min']) / 2, 'wind_speed_1');
                     } else {
                         if ($maxmin_y['max'] != '-') {
                             $sensorValues['average_y'] = $this->formatValue($maxmin_y['max'], 'wind_speed_1');
                         } else {
                             if ($maxmin_y['min'] != '-') {
                                 $sensorValues['average_y'] = $this->formatValue($maxmin_y['min'], 'wind_speed_1');
                             }
                         }
                     }
                 }
             }
             if ($for === 'single' && count($first_logs_ids) > 0) {
                 foreach ($windAverages as $key => $label) {
                     if (isset($sensorData[$key][$station_id][$sensor_id])) {
                         foreach ($sensorData[$key][$station_id][$sensor_id] as $sensorDataRecord) {
                             if (in_array($sensorDataRecord->listener_log_id, $first_logs_ids)) {
                                 $sensorValues[$label] = $sensorDataRecord->is_m == 1 ? '-' : $this->formatValue($sensorDataRecord->sensor_feature_value);
                             }
                         }
                     }
                 }
             }
             unset($sensorValues['filter_min']);
             unset($sensorValues['filter_max']);
             unset($sensorValues['filter_diff']);
         }
     }
     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++;
 }
 public function __construct($logger)
 {
     $this->aws_format = new AWSFormat();
     parent::__construct($logger);
 }
Example #15
0
 public static function getTrendForAwsPanel($stationData)
 {
     $change = 'no';
     $arrForTrend = array();
     foreach ($stationData as $trendValue) {
         $arrForTrend[] = $trendValue->sensor_feature_value;
     }
     if (SensorHandler::checkTrend($arrForTrend, 1)) {
         $change = 'up';
     } else {
         if (SensorHandler::checkTrend($arrForTrend, -1)) {
             $change = 'down';
         }
     }
     return $change;
 }
Example #16
0
 public function actionAwsSingle()
 {
     $criteria = new CDbCriteria();
     $criteria->compare('station_type', array('aws', 'awos'));
     $criteria->order = 'station_id_code asc';
     $stations = Station::model()->findAll($criteria);
     if (count($stations) > 0) {
         $session = Yii::app()->session;
         $id = isset($_REQUEST['station_id']) ? intval($_REQUEST['station_id']) : (isset($session['single_aws']['station_id']) ? $session['single_aws']['station_id'] : '');
         $station = null;
         if ($id) {
             foreach ($stations as $st) {
                 if ($id == $st->station_id) {
                     $station = $st;
                     break;
                 }
             }
         }
         $station = is_null($station) ? $stations[0] : $station;
         $log_id = isset($_REQUEST['log_id']) ? intval($_REQUEST['log_id']) : null;
         $last2Messages = ListenerLog::getAllLast2Messages(array($station->station_id), $log_id);
         if (array_key_exists($station->station_id, $last2Messages) && count($last2Messages[$station->station_id]) > 0) {
             $station->lastMessage = date('m/d/Y H:i', strtotime($last2Messages[$station->station_id][0]->measuring_timestamp));
             $next_expected = strtotime($last2Messages[$station->station_id][0]->measuring_timestamp) + $station->event_message_period * 60 + 300;
             $station->nextMessageExpected = date('m/d/Y H:i', $next_expected);
             if ($next_expected < time()) {
                 $station->nextMessageIsLates = 1;
             }
         } else {
             $station->lastMessage = 'Unknown';
         }
         if (count($last2Messages[$station->station_id]) > 1) {
             $station->previousMessage = date('m/d/Y H:i', strtotime($last2Messages[$station->station_id][1]->measuring_timestamp));
         } else {
             $station->previousMessage = 'Unknown';
         }
         $list = StationSensor::getSensorsForAWSDisplay(array($station->station_id), 'aws_single');
         $sensors = isset($list[$station->station_id]) ? $list[$station->station_id] : null;
         $handler_sensor = array();
         if (!is_null($sensors)) {
             $sensorPairs = array();
             foreach ($sensors as $sensor) {
                 $sensorPairs[$sensor->handler->handler_id_code][] = array('station_id' => $station->station_id, 'sensor_id' => $sensor->station_sensor_id, 'last_logs' => isset($last2Messages[$station->station_id]) ? $last2Messages[$station->station_id] : array(), 'aws_single_group' => $sensor->handler->aws_single_group);
             }
             $handlersDefault = array();
             SensorDBHandler::handlerWithFeature($handlersDefault, 'single');
             $sensorList = SensorHandler::getFullSensorList(array($station->station_id), $handlersDefault);
             $sensorData = SensorData::getSensorData($last2Messages, $sensorList);
             foreach ($sensorPairs as $handler_id_code => $data) {
                 $handler_obj = SensorHandler::create($handler_id_code);
                 $res = $handler_obj->getInfoForAwsPanel($data, $sensorList, $sensorData, 'single');
                 if ($res) {
                     foreach ($res as $value_sensors) {
                         foreach ($value_sensors as $value_sensor_data) {
                             if ($handler_id_code === 'WindDirection') {
                                 if ($session['single_aws']['chosen_wind_direction'] == 2) {
                                     $chosen_direction = '10minute_average';
                                 } else {
                                     if ($session['single_aws']['chosen_wind_direction'] == 1) {
                                         $chosen_direction = '2minute_average';
                                     } else {
                                         $chosen_direction = 'last';
                                     }
                                 }
                                 $value_sensor_data['chosen_wind_direction'] = $chosen_direction;
                                 $radians = ($value_sensor_data[$chosen_direction] - 90) / 180 * M_PI;
                                 //$value_sensor_data['chosen_wind_coordinates']['x'] = round(86.5+ cos($radians)*70);
                                 //$value_sensor_data['chosen_wind_coordinates']['y'] = round(86.5+ sin($radians)*70);
                                 $value_sensor_data['chosen_wind_coordinates']['x'] = round(83 + cos($radians) * 70);
                                 $value_sensor_data['chosen_wind_coordinates']['y'] = round(83 + sin($radians) * 70);
                             }
                             $value_sensor_data['handler_id_code'] = $handler_id_code;
                             $handler_sensor[$data[0]['aws_single_group']][$handler_id_code][] = $value_sensor_data;
                         }
                     }
                 }
             }
         }
         $handlers = StationCalculation::getStationCalculationHandlers(array($station->station_id));
         $calculation = array();
         if (array_key_exists($station->station_id, $handlers)) {
             foreach ($handlers[$station->station_id] as $value) {
                 $handler = CalculationHandler::create($value->handler->handler_id_code);
                 $used_sensors = $handler->getUsedSensors($station->station_id);
                 if ($used_sensors) {
                     foreach ($handler_sensor as $group => &$v2) {
                         foreach ($v2 as $handler_id_code => &$value_sensor_data) {
                             if ($value->handler->handler_id_code == 'DewPoint' && in_array($handler_id_code, array('Temperature', 'TemperatureSoil', 'TemperatureWater')) || $value->handler->handler_id_code == 'PressureSeaLevel' && in_array($handler_id_code, array('Pressure'))) {
                                 foreach ($value_sensor_data as $k4 => &$v4) {
                                     if (in_array($v4['sensor_id_code'], $used_sensors)) {
                                         $calculation[$group][$value->handler->handler_id_code] = 1;
                                         $v4[$value->handler->handler_id_code] = $handler->getCalculatedValue($station->station_id, $last2Messages[$station->station_id]);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
         $session['single_aws'] = array('station_id' => $station->station_id, 'chosen_wind_direction' => $session['single_aws']['chosen_wind_direction']);
     }
     $speciReport = null;
     if (count($last2Messages[$station->station_id]) > 0) {
         $criteria = new CDbCriteria();
         $criteria->with = array('ScheduleReportToStation.schedule_report');
         $criteria->compare('report_type', 'speci');
         $criteria->compare('ScheduleReportToStation.station_id', $station->station_id);
         //			$criteria->compare('is_last', 1);
         $criteria->compare('listener_log_id', $last2Messages[$station->station_id][0]->log_id);
         //			$criteria->order = 't.updated desc';
         $criteria->order = 't.created desc';
         $criteria->limit = 1;
         $speciReport = ScheduleReportProcessed::model()->find($criteria);
         if (is_null($speciReport)) {
             $reportRecord = ScheduleReport::model()->findByAttributes(array('report_type' => 'speci', 'station_id' => $station->station_id));
             if (!is_null($reportRecord)) {
                 $speciReport = new ScheduleReportProcessed();
                 $speciReport->schedule_id = $reportRecord->schedule_id;
                 $speciReport->listener_log_id = $last2Messages[$station->station_id][0]->log_id;
                 $speciReport->is_processed = 0;
                 $speciReport->check_period_start = $last2Messages[$station->station_id][0]->measuring_timestamp;
                 $speciReport->check_period_end = $last2Messages[$station->station_id][0]->measuring_timestamp;
                 $speciReport->save();
             }
         }
     }
     //        echo "<pre>";
     //        print_r($handler_sensor);
     //        echo "</pre>";exit;
     $template = 'aws_single';
     $render_data = array('stations' => $stations, 'station' => $station, 'last_logs' => $last2Messages[$station->station_id], 'handler_sensor' => $handler_sensor, 'calculation' => $calculation, 'speciReport' => $speciReport);
     if (Yii::app()->request->isAjaxRequest) {
         $this->renderPartial($template, array('render_data' => $render_data));
     } else {
         $this->render('autorefresh_aws_single', array('render_data' => $render_data, 'template' => $template));
     }
 }
Example #17
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);
 }
Example #18
0
 public function actionMsgGeneration()
 {
     ini_set('memory_limit', '-1');
     $form = new GenerateMessageForm();
     $messages = array();
     $sensors = array();
     if (Yii::app()->request->isPostRequest && (isset($_POST['generate']) || isset($_POST['import']))) {
         $form->attributes = $_POST['GenerateMessageForm'];
         if ($form->validate()) {
             $sensors = array();
             if ($form->sensor_id) {
                 $sql = "SELECT `t1`.`station_sensor_id`, `t1`.`sensor_id_code`, `t2`.`handler_id_code`, `t3`.`feature_code`, `t4`.`code` AS `metric_code` \n                            FROM `" . StationSensor::model()->tableName() . "` `t1`\n                            LEFT JOIN `" . SensorDBHandler::model()->tableName() . "`      `t2` ON `t2`.`handler_id` = `t1`.`handler_id`\n                            LEFT JOIN `" . StationSensorFeature::model()->tableName() . "` `t3` ON `t3`.`sensor_id`  = `t1`.`station_sensor_id`\n                            LEFT JOIN `" . RefbookMetric::model()->tableName() . "`        `t4` ON `t4`.`metric_id`  = `t3`.`metric_id`\n                            WHERE `t1`.`station_id` = '" . $form->station_id . "' AND `t1`.`station_sensor_id` IN (" . implode(',', $form->sensor_id) . ")";
                 $res = Yii::app()->db->createCommand($sql)->queryAll();
                 if ($res) {
                     foreach ($res as $key => $value) {
                         if (!isset($sensors[$value['station_sensor_id']])) {
                             $sensors[$value['station_sensor_id']] = array('station_sensor_id' => $value['station_sensor_id'], 'sensor_id_code' => $value['sensor_id_code'], 'handler_id_code' => $value['handler_id_code']);
                         }
                         $sensors[$value['station_sensor_id']]['features'][$value['feature_code']] = $value['metric_code'];
                     }
                 }
             }
             $i = $form->start_timestamp;
             while ($i <= $form->end_timestamp) {
                 $messages[$i]['timestamp'] = $i;
                 $i = $i + $form->interval * 60;
             }
             foreach ($messages as $key => $value) {
                 if ($form->choosed_station['station_type'] === 'rain') {
                     $messages[$key]['parts'][] = 'D';
                     $messages[$key]['parts'][] = $form->choosed_station['station_id_code'];
                     $messages[$key]['parts'][] = date('ymd', $key);
                     $messages[$key]['parts'][] = date('Hi', $key);
                     $messages[$key]['parts'][] = str_pad(rand(100, 135), 3, "0", STR_PAD_LEFT);
                     $messages[$key]['parts'][] = '00';
                 } else {
                     $messages[$key]['parts'][] = 'D';
                     $messages[$key]['parts'][] = $form->choosed_station['station_id_code'];
                     $messages[$key]['parts'][] = date('ymd', $key);
                     $messages[$key]['parts'][] = date('Hi', $key);
                     $messages[$key]['parts'][] = '00';
                 }
                 $sensors_values = array();
                 if ($sensors) {
                     foreach ($sensors as $k1 => $v1) {
                         $handler = SensorHandler::create($v1['handler_id_code']);
                         $random_value = $handler->getRandomValue($v1['features']);
                         $sensors_values[] = $v1['sensor_id_code'] . $random_value;
                     }
                     shuffle($sensors_values);
                     foreach ($sensors_values as $k1 => $v1) {
                         $messages[$key]['parts'][] = $v1;
                     }
                 }
                 $crc = It::prepareCRC(implode('', $messages[$key]['parts']));
                 $messages[$key]['parts'][] = $crc;
                 array_push($messages[$key]['parts'], '$');
                 array_unshift($messages[$key]['parts'], '@');
             }
         }
     }
     $messages_display = array();
     $messages_copy = array();
     foreach ($messages as $key => $value) {
         $messages_display[] = implode(' ', $value['parts']);
         $messages_copy[] = implode('', $value['parts']);
     }
     $station_sensors = StationSensor::getList($form->station_id);
     if ($station_sensors) {
         foreach ($station_sensors as $key => $value) {
             $station_sensors[$key]['checked'] = 1;
         }
     }
     if (isset($_POST['GenerateMessageForm']['sensor_id'])) {
         if ($station_sensors) {
             foreach ($station_sensors as $key => $value) {
                 $station_sensors[$key]['checked'] = in_array($value['station_sensor_id'], $_POST['GenerateMessageForm']['sensor_id']) ? 1 : 0;
             }
         }
     }
     $this->render('msg_generation', array('form' => $form, 'messages_display' => $messages_display, 'messages_copy' => $messages_copy, 'station_sensors' => $station_sensors));
 }
Example #19
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);
                 }
             }
         }
     }
 }
 /**
  * @var $stationForm configForm
  * **/
 public function run($args)
 {
     //        error_reporting(null);
     ini_set('display_errors', 1);
     $this->_logger = LoggerFactory::getFileLogger('GenerateMessageCommand');
     //        $this->_logger = LoggerFactory::getConsoleLogger();
     $this->_logger->log('start');
     //       $args:
     //       $args[0] AWS01
     //       $args[1] "sensors:TS1;TS2;"
     $station_id_code = false;
     if (preg_match('/^([A-Z,a-z,0-9]{4,5})$/', $args[0], $matchesStations)) {
         $station_id_code = $matchesStations[1];
     } else {
         $this->_logger->log(' Station ID can contain only Letters (A-Z) and Figures (1-9), and must be of 4(rain) or 5(AWS) chars length.');
     }
     $sensor_id_codes = array();
     if (isset($args[1])) {
         if (preg_match("/^sensors:([A-Za-z1-9;]+)/", $args[1], $matchesSensors)) {
             $sensor_id_code = explode(';', $matchesSensors[1]);
             $sensor_id_codes = array_values($sensor_id_code);
             $sensor_id_codes_count = count($sensor_id_codes);
             for ($i = 0; $i < $sensor_id_codes_count; $i++) {
                 if (!preg_match('/^([A-Z,a-z]{2})([1-9]{1})$/', $sensor_id_codes[$i], $matches)) {
                     unset($sensor_id_codes[$i]);
                     $this->_logger->log('Sensor ID should contain two letters and 1 digit. Ex.: TP1');
                 }
             }
             $sensor_id_codes = array_values($sensor_id_codes);
         }
     }
     $station = Station::getStationByCode($station_id_code, array('sensors.handler', 'sensors.features.metric'));
     //            $sql = "SELECT `t1`.`station_sensor_id`, `t1`.`sensor_id_code`,  `t2`.`handler_id_code`, `t3`.`feature_code`, `t4`.`code` AS `metric_code`
     //                            FROM `".StationSensor::model()->tableName()."` `t1`
     //                            LEFT JOIN `".SensorDBHandler::model()->tableName()."`      `t2` ON `t2`.`handler_id` = `t1`.`handler_id`
     //                            LEFT JOIN `".StationSensorFeature::model()->tableName()."` `t3` ON `t3`.`sensor_id`  = `t1`.`station_sensor_id`
     //                            LEFT JOIN `".RefbookMetric::model()->tableName()."`        `t4` ON `t4`.`metric_id`  = `t3`.`metric_id`
     //                            WHERE `t1`.`station_id` = '".$station_id."' AND `t1`.`station_sensor_id` IN (".implode(',',$sensor_id).")";
     //            $res = Yii::app()->db->createCommand($sql)->queryAll();
     if ($station) {
         TimezoneWork::set($station->timezone_id);
         $sensors = array();
         foreach ($station->sensors as $key => $sensor) {
             if (in_array($sensor->sensor_id_code, $sensor_id_codes) || count($sensor_id_codes) == 0) {
                 if (!isset($sensors[$sensor->station_sensor_id])) {
                     $sensors[$sensor->station_sensor_id] = array('station_sensor_id' => $sensor->station_sensor_id, 'sensor_id_code' => $sensor->sensor_id_code, 'handler_id_code' => $sensor->handler->handler_id_code);
                 }
                 foreach ($sensor->features as $feature) {
                     if (is_object($feature->metric)) {
                         $sensors[$sensor->station_sensor_id]['features'][$feature->feature_code] = $feature->metric->code;
                     }
                 }
             }
         }
         $i = time();
         $messages[$i]['timestamp'] = $i;
         $this->_logger->log(__METHOD__ . ': sensors ' . print_r($sensors['sensor_id_code'], 1));
         foreach ($messages as $key => $value) {
             if ($station->station_type === 'rain') {
                 $messages[$key]['parts'][] = 'D';
                 $messages[$key]['parts'][] = $station->station_id_code;
                 $messages[$key]['parts'][] = date('ymd', $key);
                 $messages[$key]['parts'][] = date('Hi', $key);
                 $messages[$key]['parts'][] = str_pad(rand(100, 135), 3, "0", STR_PAD_LEFT);
                 $messages[$key]['parts'][] = '00';
             } else {
                 $messages[$key]['parts'][] = 'D';
                 $messages[$key]['parts'][] = $station->station_id_code;
                 $messages[$key]['parts'][] = date('ymd', $key);
                 $messages[$key]['parts'][] = date('Hi', $key);
                 $messages[$key]['parts'][] = '00';
             }
             $sensors_values = array();
             if ($sensors) {
                 foreach ($sensors as $k1 => $v1) {
                     $handler = SensorHandler::create($v1['handler_id_code']);
                     $random_value = $handler->getRandomValue($v1['features']);
                     $sensors_values[] = $v1['sensor_id_code'] . $random_value;
                 }
                 shuffle($sensors_values);
                 foreach ($sensors_values as $k1 => $v1) {
                     $messages[$key]['parts'][] = $v1;
                 }
             }
             $crc = It::prepareCRC(implode('', $messages[$key]['parts']));
             $messages[$key]['parts'][] = $crc;
             array_push($messages[$key]['parts'], '$');
             array_unshift($messages[$key]['parts'], '@');
         }
         $messages_display = array();
         $messages_copy = array();
         foreach ($messages as $key => $value) {
             $messages_display[] = implode(' ', $value['parts']);
             $messages_copy[] = implode('', $value['parts']);
         }
         $this->_logger->log(__METHOD__ . ': $messages_copy ' . print_r($messages_copy, 1));
         foreach ($messages_copy as $msg) {
             ListenerLogTemp::addNew($msg, 0, 1, 'import', 0);
         }
     } else {
         $this->_logger->log(__METHOD__ . ': has no stations like ' . $args[0]);
     }
 }