'晴', 1 => '多云', 2 => '阴', 3 => '阵雨', 4 => '雷阵雨', 5 => '雷阵雨伴有冰雹', 6 => '雨夹雪', 7 => '小雨', 8 => '中雨', 9 => '大雨', 10 => '暴雨', 11 => '大暴雨', 12 => '特大暴雨', 13 => '阵雪', 14 => '小雪', 15 => '中雪', 16 => '大雪', 17 => '暴雪', 18 => '雾', 19 => '冻雨', 20 => '沙尘暴', 21 => '小到中雨', 22 => '中到大雨', 23 => '大到暴雨', 24 => '暴雨到大暴雨', 25 => '大暴雨到特大暴雨', 26 => '小到中雪', 27 => '中到大雪', 28 => '大到暴雪', 29 => '浮尘', 30 => '扬沙', 31 => '强沙尘暴', 53 => '霾', 99 => '无', 32 => '浓雾', 49 => '强浓雾', 54 => '中度霾', 55 => '重度霾', 56 => '严重霾', 57 => '大雾', 58 => '特强浓雾', 301 => '雨', 302 => '雪', ]; /** * @param $city_id * @return mixed */ public function getWeatherData($city_id) { $this->city_id = $city_id; // $city_id = is_numeric($city_id) ? ("CN" . $city_id) : $city_id; $key = $this->getKey(); $caiyun_version = GlobalConfig::getData("caiyun_version"); $url = sprintf("https://api.caiyunapp.com/v%s/%s/%s/weather_2.json?alert=true&dailysteps=15", $caiyun_version, $key, $this->getCoodinate($city_id)); $data1 = Curl::get($url); $data1 = json_decode($data1, true); $data2=Redis::instance()->get("weather:$city_id"); if (!$data2){ $url = sprintf("https://apip.weatherdt.com/plugin/data?key=FKh9Y6PdLP&location=%s", $city_id); $data2 = Curl::get($url); $data2 = json_decode($data2, true); Redis::instance()->set("weather:$city_id", $data2,7200); } $data = $this->parseData($data1, $data2); $i = 0; while ($data['Weather']['now']['cond_txt'] == "" && $i < 2) {//数据有误,重试3次 $log_file = APP_DIR . "/logs/" . date("Ymd") . "_null.log"; file_put_contents($log_file, sprintf("%s\t\tcity_id:%s", date("Y-m-d H:i:s"), $city_id) . "\t\tdata1:" . json_encode($data1) . "\t\tdata2:".json_encode($data2)."\r\n", FILE_APPEND); Warming::semdMail("no_data", "混合接口", ALERT_TOTAL, $log_file); $url = sprintf("https://api.caiyunapp.com/v%s/%s/%s/weather_2.json?alert=true&dailysteps=15", $caiyun_version, $key, $this->getCoodinate($city_id)); $data1 = Curl::get($url); $url = sprintf("https://apip.weatherdt.com/plugin/data?key=FKh9Y6PdLP&location=%s", $city_id); $data2 = Curl::get($url); $data1 = json_decode($data1, true); $data2 = json_decode($data2, true); Redis::instance()->set("weather:$city_id", $data2,7200); $data = $this->parseData($data1, $data2); $i++; } return $data; } private function getKey() { $keys = GlobalConfig::getData("caiyun_key"); $key = date("Ymd_") . $keys; Redis::instance()->incr($key); return $keys; } /** * * @param $data * @param null $data2 * @return array */ public function parseData($data, $data2 = null) { $originData = $data; $return = []; $weather = []; $weather['basic'] = [ 'location' => $this->location, 'city_code' => $this->city_id, 'update' => date("Y-m-d H:i", $data['server_time']) ]; $weather['status'] = $originData['status'] ?: "ok"; $result = $originData['result']; // $weather['key'] = $k; $weather['air_now_city'] = [ "aqi" => (string)$result['realtime']['air_quality']['aqi']['chn'] ?? "", // ->a3 "qlty" => (string)$result['realtime']['air_quality']['description']['chn'] ?? "", // ->a4 "pm25" => (string)$result['realtime']['air_quality']['pm25'] ?? "", // ->a5 "pm10" => (string)$result['realtime']['air_quality']['pm10'] ?? "", // ->a6 "no2" => (string)$result['realtime']['air_quality']['no2'] ?? "", // ->a7 "so2" => (string)$result['realtime']['air_quality']['so2'] ?? "" ]; $weather['alarm'] = [ "level" => "", // ->a9 "link" => $this->getAlert($result['alert']['content'][0]['code']), // ->b1 "type" => "", // ->b2 'alertId' => (string)$result['alert']['content'][0]['alertId'] ?? "", "title" => (string)$result['alert']['content'][0]['title'] ?? "",// ->z2 "description" => (string)($result['alert']['content'][0]['description'] ? $result['alert']['content'][0]['description'] . sprintf("(来源:%s)", $result['alert']['content'][0]['source']) : ""), // ->z3 "pubtimestamp" => (string)($result['alert']['content'] ? date("Y-m-d H:i", $result['alert']['content'][0]['pubtimestamp']) : ""), // ->z4 "location" => (string)$result['alert']['content'][0]['location'] ?? "", // ->z5 "status" => (string)$result['alert']['content'][0]['status'] ?? "" // ->z6 ]; $weather['now'] = [ "cond_txt" => $this->getSkycon($result['realtime']['skycon']), // ->b3 "fl" => (string)(intval($result['realtime']['apparent_temperature']) ?: ""),// ->b4 "hum" => (string)intval($result['realtime']['humidity'] * 100), // ->b5 "pres" => (string)intval($result['realtime']['pressure'] / 100), // ->b6 "tmp" => (string)(intval($result['realtime']['temperature']) ?: ""), // ->b7 "vis" => (string)$result['realtime']['visibility'] ?: "", // ->b8 "wind_dir" => (string)$this->getWindDirect($result['realtime']['wind']['direction']) ?: "", // ->b9 "wind_sc" => (string)$this->getWindSpeed($result['realtime']['wind']['speed'])['level'] ?: "", // ->c1 "sr" => (string)$result['daily']['astro'][0]['sunrise']['time'], // ->c2 "ss" => (string)$result['daily']['astro'][0]['sunset']['time'], // ->c3 'forecast_keypoint' => (string)$result['forecast_keypoint'] ?? "", 'description' => (string)$result['hourly']['description'] ?? "", ]; if (!empty($result['daily'])) { if (!empty($data2['forecast'])) { $i = 0; $date = date("Y-m-d", strtotime($data2['forecast']['date'])); foreach ($data2['forecast']['forecast'] as $key => $value) { $temp = [ "cond_txt_d" => $this->weather_code[intval($value['tqw_code_d'])] ?: ($value['tqw_code_d'] ?: ""),//$value['tqw_code_d'] ?: "", "cond_txt_n" => $this->weather_code[intval($value['tqw_code_n'])] ?: ($value['tqw_code_n'] ?: ""),//$value['tqw_code_n'] ?: "", "date" => date("Y-m-d", strtotime("+$i days", strtotime($date))), "tmp_max" => $value['tmp_max'] ?: "", "tmp_min" => $value['tmp_min'] ?: "", "wind_dir" => $value['wind_dir_d_txt'] ?: "", "wind_sc" => $value['wind_sc_d_txt'] ?: "", ]; $i++; $weather['daily_forecast'][] = $temp; } } $j = 0; foreach ($result['daily']['skycon_08h_20h'] as $key => $value) { if ($j < $i) { $j++; continue; } $temp = [ "cond_txt_d" => $this->getSkycon($value['value']), "cond_txt_n" => $this->getSkycon($result['daily']['skycon_20h_32h'][$key]['value']), "date" => date("Y-m-d", strtotime($value['date'])), "tmp_max" => (string)intval($result['daily']['temperature'][$key]['max']), "tmp_min" => (string)intval($result['daily']['temperature'][$key]['min']), "wind_dir" => (string)$this->getWindDirect($result['daily']['wind'][$key]['avg']['direction']), "wind_sc" => (string)$this->getWindSpeed($result['daily']['wind'][$key]['avg']['speed'])['level'], ]; $weather['daily_forecast'][] = $temp; } } if (!empty($result['hourly'])) { $i = 0; foreach ($result['hourly']['temperature'] as $key => $value) { if ($i >= 24) { break; } $i++; $temp = [ 'cond_txt' => $this->getSkycon($result['hourly']['skycon'][$key]['value']), 'time' => date("Y-m-d H:i", strtotime($value['datetime'])), 'tmp' => (string)intval($value['value']), ]; $weather['hourly'][] = $temp; } } $weather['lifestyle'] = [ [ 'type' => 'flu', 'brf' => $result['daily']['life_index']['coldRisk'][0]['desc'], 'txt' => '' ], [ 'type' => 'cw', 'brf' => $result['daily']['life_index']['carWashing'][0]['desc'], 'txt' => '' ], [ 'type' => 'uv', 'brf' => $result['daily']['life_index']['ultraviolet'][0]['desc'], 'txt' => '' ], [ 'type' => 'comf', 'brf' => $result['daily']['life_index']['comfort'][0]['desc'], 'txt' => '' ], [ 'type' => 'drsg', 'brf' => $result['daily']['life_index']['dressing'][0]['desc'], 'txt' => '' ], ]; $return['Weather'] = $weather; $return['source'] = "caiyun"; return $return; } /** * @param $code * @return array|mixed|string */ private function getCoodinate($code) { $key = "coodinateData"; $coodinate = Redis::instance()->hGet($key, $code); // unset($coodinate); if (!$coodinate['lo'] || !$coodinate['la']) { $coodinate = CityToCoordinate::getData($code); if (!empty($coodinate)) { // $coodinate = $coodinate['lo'] . "," . $coodinate['la']; Redis::instance()->hSet($key, $code, $coodinate); } } $this->location = $coodinate['location']; return $coodinate['lo'] . "," . $coodinate['la']; } /** * 获取风向 * @param $degree * @return mixed */ private function getWindDirect($degree) { $directArr = ["北风", "东北风", "东北风", "东北风", "东风", "东南风", "东南风", "东南风", "南风", "西南风", "西南风", "西南风", "西风", "西北风", "西北风", "西北风"]; $index = 0; if (348.75 <= $degree && $degree <= 360) { $index = 0; } else { if (0 <= $degree && $degree <= 11.25) { $index = 0; } else if (11.25 < $degree && $degree <= 33.75) { $index = 1; } else if (33.75 < $degree && $degree <= 56.25) { $index = 2; } else if (56.25 < $degree && $degree <= 78.75) { $index = 3; } else if (78.75 < $degree && $degree <= 101.25) { $index = 4; } else if (101.25 < $degree && $degree <= 123.75) { $index = 5; } else if (123.75 < $degree && $degree <= 146.25) { $index = 6; } else if (146.25 < $degree && $degree <= 168.75) { $index = 7; } else if (168.75 < $degree && $degree <= 191.25) { $index = 8; } else if (191.25 < $degree && $degree <= 213.75) { $index = 9; } else if (213.75 < $degree && $degree <= 236.25) { $index = 10; } else if (236.25 < $degree && $degree <= 258.75) { $index = 11; } else if (258.75 < $degree && $degree <= 281.25) { $index = 12; } else if (281.25 < $degree && $degree <= 303.75) { $index = 13; } else if (303.75 < $degree && $degree <= 326.25) { $index = 14; } else if (326.25 < $degree && $degree < 348.75) { $index = 15; } } return $directArr[$index]; } private function getWindSpeed($speed) { $wind = [ 'name' => '无风', 'level' => 0 ]; if ($speed > 1 && $speed <= 5) { $wind = [ 'name' => '软风', 'level' => 1 ]; } if ($speed > 5 && $speed <= 11) { $wind = [ 'name' => '轻风', 'level' => 2 ]; } if ($speed > 11 && $speed <= 19) { $wind = [ 'name' => '微风', 'level' => 3 ]; } if ($speed > 19 && $speed <= 28) { $wind = [ 'name' => '和风', 'level' => 4 ]; } if ($speed > 28 && $speed <= 38) { $wind = [ 'name' => '清风', 'level' => 5 ]; } if ($speed > 38 && $speed <= 49) { $wind = [ 'name' => '强风', 'level' => 6 ]; } if ($speed > 49 && $speed <= 61) { $wind = [ 'name' => '劲风', 'level' => 7 ]; } if ($speed > 61 && $speed <= 74) { $wind = [ 'name' => '大风', 'level' => 8 ]; } if ($speed > 74 && $speed <= 88) { $wind = [ 'name' => '烈风', 'level' => 9 ]; } if ($speed > 88 && $speed <= 102) { $wind = [ 'name' => '狂风', 'level' => 10 ]; } if ($speed > 102 && $speed <= 117) { $wind = [ 'name' => '暴风', 'level' => 11 ]; } if ($speed > 117 && $speed <= 134) { $wind = [ 'name' => '台风', 'level' => 12 ]; } if ($speed > 134 && $speed <= 149) { $wind = [ 'name' => '台风', 'level' => 13 ]; } if ($speed > 149 && $speed <= 166) { $wind = [ 'name' => '台风', 'level' => 14 ]; } if ($speed > 166 && $speed <= 183) { $wind = [ 'name' => '台风', 'level' => 15 ]; } if ($speed > 183 && $speed <= 201) { $wind = [ 'name' => '台风', 'level' => 16 ]; } if ($speed > 201 && $speed <= 220) { $wind = [ 'name' => '台风', 'level' => 17 ]; } if ($speed > 220) { $wind = [ 'name' => '台风', 'level' => 18 ]; } return $wind; } private function getSkycon($skycon) { $arr = [ 'CLEAR_DAY' => '晴', 'CLEAR_NIGHT' => '晴', 'PARTLY_CLOUDY_DAY' => '多云', 'PARTLY_CLOUDY_NIGHT' => '多云', 'CLOUDY' => '阴', 'LIGHT_HAZE' => '轻度雾霾', 'MODERATE_HAZE' => '中度雾霾', 'HEAVY_HAZE' => '重度雾霾', 'LIGHT_RAIN' => '小雨', 'MODERATE_RAIN' => '中雨', 'HEAVY_RAIN' => '大雨', 'STORM_RAIN' => '暴雨', 'FOG' => '雾', 'LIGHT_SNOW' => '小雪', 'MODERATE_SNOW' => '中雪', 'HEAVY_SNOW' => '大雪', 'STORM_SNOW' => '暴雪', 'DUST' => '浮尘', 'SAND' => '沙尘', 'WIND' => '大风', 'SLEET' => '雨夹雪', 'THUNDER_SHOWER' => '雷阵雨', 'HAIL' => '冰雹', ]; return $arr[$skycon] ?? ""; } private function getAlert($code, $type = 1) { $alert_type = [ '01' => '台风', '02' => '暴雨', '03' => '暴雪', '04' => '寒潮', '05' => '⼤风', '06' => '沙尘暴', '07' => '高温', '08' => '干旱', '09' => '雷电', '10' => '冰雹', '11' => '霜冻', '12' => '大雾', '13' => '霾', '14' => '道路结冰', '15' => '森林火灾', '16' => '雷雨大风', ]; $alert_level = [ '01' => '蓝色', '02' => '黄色', '03' => '橙色', '04' => '红色', ]; $code_1 = substr($code, 0, 2); $code_2 = substr($code, 2, 2); if ($type == 1) { return $code ? $alert_type[$code_1] . $alert_level[$code_2] . '预警' : ""; } else { return $alert_level[$code_2] ?? ""; } } }