⚡ Lightning Data API v1.0

API Dữ liệu Sét Thời gian thực

Tích hợp dữ liệu sét (lightning) vào ứng dụng của bạn chỉ trong vài dòng code. Dữ liệu bao gồm vị trí, cường độ, và nhiều tham số kỹ thuật khác — cập nhật liên tục từ mạng lưới cảm biến đa nguồn.

💡
Base URL: https://evntools.com/api/v1
Tất cả request đều cần header X-API-Key hợp lệ.

🔑 Xác thực (Authentication)

Mọi request tới API đều phải kèm header X-API-Key chứa API Key của bạn.

⚠️
Không chia sẻ API Key của bạn công khai (không đưa lên GitHub, forum...). Nếu bị lộ, hãy liên hệ Admin để thu hồi và cấp lại.
HTTP Header
X-API-Key: evn_your_api_key_here

Trạng thái Key

active✅ Hoạt độngKey đang dùng được bình thường
pending⏳ Chờ duyệtĐã tạo, chờ Admin kích hoạt
expired⏰ Hết hạnCần gia hạn hoặc nâng cấp gói
revoked🚫 Bị khóaKey bị Admin thu hồi

⚡ Quickstart — 1 phút là chạy được

Gọi API lấy danh sách sét trong 1 giờ qua:

cURL
# Lấy dữ liệu sét 1 giờ qua từ tất cả nguồn curl -X GET "https://evntools.com/api/v1/lightning?source=all&hours=1" \ -H "X-API-Key: evn_your_api_key_here"
Python
import requests API_KEY = "evn_your_api_key_here" BASE_URL = "https://evntools.com/api/v1" headers = {"X-API-Key": API_KEY} params = {"source": "all", "hours": 1} resp = requests.get(BASE_URL + "/lightning", headers=headers, params=params) data = resp.json() print(f"Tổng số sét: {data['count']}") for bolt in data["data"]: print(f" [{bolt['time']}] lat={bolt['lat']:.4f}, lon={bolt['lon']:.4f}, amp={bolt.get('amplitude','N/A')} kA")
JavaScript (Fetch)
const API_KEY = 'evn_your_api_key_here'; const BASE_URL = 'https://evntools.com/api/v1'; async function getLightning(hours = 1, source = 'all') { const url = `${BASE_URL}/lightning?source=${source}&hours=${hours}`; const resp = await fetch(url, { headers: { 'X-API-Key': API_KEY } }); if (!resp.ok) throw new Error(`API Error: ${resp.status}`); return resp.json(); } // Sử dụng getLightning(2, 'all').then(data => { console.log(`Có ${data.count} tia sét`); data.data.forEach(b => console.log(b)); });
C# (.NET)
using System.Net.Http; using System.Net.Http.Json; var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-API-Key", "evn_your_api_key_here"); var url = "https://evntools.com/api/v1/lightning?source=all&hours=1"; var result = await client.GetFromJsonAsync<LightningResponse>(url); Console.WriteLine($"Tổng: {result!.Count} tia sét");
PHP (cURL)
<?php $ch = curl_init(); $url = "https://evntools.com/api/v1/lightning?source=all&hours=1"; curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-API-Key: evn_your_api_key_here" ] ]); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); echo "Tổng số sét: " . $data['count'] . "\n"; ?>
Go
package main import ( "fmt" "net/http" "io/ioutil" ) func main() { url := "https://evntools.com/api/v1/lightning?source=all&hours=1" req, _ := http.NewRequest("GET", url, nil) req.Header.Add("X-API-Key", "evn_your_api_key_here") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) fmt.Println(string(body)) }

📦 Gói Cước & Giới hạn

🌏
Vùng phủ dữ liệu: Dữ liệu sét đầy đủ cho 4 quốc gia — Việt Nam 🇻🇳, Lào 🇱🇦, Thái Lan 🇹🇭, Campuchia 🇰🇭.
Có nhu cầu phủ vùng riêng (quốc gia khác, khu vực đặc biệt)? Liên hệ Admin để được hỗ trợ riêng.

Mỗi API Key được gắn với một gói cước xác định số request/ngày, tốc độ gọi, và nguồn dữ liệu được phép truy cập.

⚡ Test (1 ngày)
Req/ngày1,500
Rate/phút15
Bản ghi/req2,000
Phạm viBán kính 100 km
NguồnTất cả nguồn (Nguồn M, Nguồn V, Nguồn W, Nguồn H)
Lịch sử30 ngày
Thời hạn1 ngày
🆓 Free/Trial
Req/ngày100
Rate/phút2
Bản ghi/req500
Phạm viBán kính ≤ 10 km
NguồnNguồn H
Lịch sửKhông (Realtime)
Tham sốVị trí cơ bản
🥈 Basic
Req/ngày1,500
Rate/phút5
Bản ghi/req500
Phạm viBán kính ≤ 30 km
NguồnNguồn H, Nguồn W
Lịch sử24 giờ
Tham sốVị trí + tọa độ, cường độ
ℹ️
Gói Enterprise: Không giới hạn request, tối đa 5,000 bản ghi/request, lịch sử 1 năm, toàn quyền quét dữ liệu toàn quốc, hỗ trợ Webhook đẩy dữ liệu chủ động. Liên hệ Admin để đăng ký.

💡 Giải thích Cơ chế gọi API & Các thông số gói

Để tích hợp API một cách hiệu quả và tiết kiệm tài nguyên hệ thống, dưới đây là quy định kỹ thuật bắt buộc và giải thích chi tiết:

🔄 1. Req/ngày & Tần suất gọi chuẩn

Mỗi lần ứng dụng gửi 1 yêu cầu HTTP GET đến máy chủ để lấy dữ liệu được tính là 1 request.

⚠️ QUY ĐỊNH TẦN SUẤT GỌI: TỐI THIỂU 1 – 2 PHÚT / LẦN
Mạng lưới cảm biến sét cập nhật theo chu kỳ 1 – 2 phút. Vì vậy, ứng dụng bắt buộc gọi với khoảng cách tối thiểu 1 – 2 phút / lần (không gọi theo giây để tránh lãng phí băng thông và làm quá tải hệ thống):
• 5 phút / lần: Gọi 12 lần/giờ → 288 req/ngày (Chuẩn cho web, bảng tin, app theo dõi thời tiết).
• 2 phút / lần: Gọi 30 lần/giờ → 720 req/ngày (Khuyến nghị chuẩn cho trạm biến áp, nhà máy điện).
• 1 phút / lần: Gọi 60 lần/giờ → 1,440 req/ngày (Tần suất tối đa cho hệ thống cảnh báo dông sét).
👉 Gói Basic (1,500 req/ngày) là đã quá đủ để ứng dụng gọi liên tục mỗi 1 phút suốt 24/24 giờ.
⚡ 2. Rate/phút (Tốc độ gọi tối đa)

Giới hạn số request tối đa trong vòng 60 giây nhằm bảo vệ máy chủ, ngăn chặn tình trạng spam và lỗi vòng lặp vô tận (infinite loop).

• Gói Basic (5 req/phút): Đảm bảo ứng dụng gửi request cách nhau hợp lý (tối thiểu 12s – 60s/lần).
• Gói Premium (20 req/phút): Cho phép gọi đồng thời nhiều trạm/điểm đo trên cùng 1 hệ thống.
⛔ Lưu ý: Tuyệt đối không lập trình gọi theo giây (1s hay 5s/lần) vì server sẽ tự động từ chối với mã lỗi HTTP 429 (Rate Limit Exceeded).
📅 3. Lịch sử 24h, 30 ngày, 1 năm

Đây là độ sâu thời gian (khoảng lùi về quá khứ) bạn được phép truy vấn thông qua tham số hours, chứ không phải thời hạn sử dụng của API Key:

• Giám sát Real-time: Ứng dụng chỉ cần truyền hours=1 (lấy sét 15–60 phút qua).
• Phân tích sự cố kỹ thuật: Khi đường dây điện/trạm biến áp nhảy aptomat lúc 2h sáng hôm qua hoặc tuần trước, kỹ sư truyền hours=24 hoặc hours=720 (30 ngày) để tra cứu lại toàn bộ các tia sét đánh vào vị trí đó để lập biên bản sự cố.
🎯 4. Bán kính (Radius) vs Toàn vùng

Hệ thống phân cấp phạm vi truy cập để bảo vệ tài sản dữ liệu và tối ưu hiệu năng:

• Lấy theo bán kính (/lightning/radius): Áp dụng cho tất cả các gói. Khách truyền tọa độ tâm trạm/công trình và bán kính (Free ≤ 10km, Basic ≤ 30km, Premium ≤ 100km). Server tính sẵn khoảng cách distance_km từ tâm đến tia sét (gần → xa). Cực kỳ nhẹ máy, tiết kiệm pin và băng thông.
• Lấy toàn vùng (/lightning): Dành riêng cho Gói Premium & Enterprise. Trả về toàn bộ sét trên phạm vi quốc gia phục vụ các trung tâm điều độ hoặc bản đồ radar diện rộng.

📱 Ngôn ngữ & Nền tảng Hỗ trợ

API được xây dựng theo chuẩn RESTful API qua HTTPS, trả về định dạng JSON UTF-8. Vì vậy, bất kỳ ngôn ngữ lập trình hoặc nền tảng nào gửi được HTTP Request đều tích hợp được dễ dàng:

🌐 Web Frontend
JavaScript, TypeScript, React, Vue, Angular, Svelte, Next.js, HTML5/Leaflet/Mapbox
🤖 Mobile Android
Kotlin, Java (sử dụng Retrofit2, OkHttp, Ktor, Volley)
🍎 Mobile iOS
Swift, SwiftUI, Objective-C (sử dụng URLSession, Alamofire)
📲 Cross-Platform
Flutter (Dart http/Dio), React Native, Ionic, .NET MAUI
🖥️ Server & Backend
Python, Node.js, PHP, C# (.NET Core), Java Spring, Go, Rust
📟 IoT & Nhúng
ESP32 / ESP8266 (Arduino C++), Raspberry Pi (kích hoạt còi/đèn hú báo động khi có sét)

Ví dụ tích hợp trên các Nền tảng:

Kotlin (Android OkHttp)
// Android OkHttp Request val client = OkHttpClient() val request = Request.Builder() .url("https://evntools.com/api/v1/lightning/radius?lat=21.0285&lon=105.854&radius=50&hours=1") .addHeader("X-API-Key", "evn_your_api_key_here") .build() client.newCall(request).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { val jsonData = response.body?.string() println("Dữ liệu sét: $jsonData") } override fun onFailure(call: Call, e: IOException) { e.printStackTrace() } })
Swift (iOS URLSession)
// iOS Swift URLSession let url = URL(string: "https://evntools.com/api/v1/lightning/radius?lat=21.0285&lon=105.854&radius=50&hours=1")! var request = URLRequest(url: url) request.setValue("evn_your_api_key_here", forHTTPHeaderField: "X-API-Key") URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data else { return } if let jsonString = String(data: data, encoding: .utf8) { print("Sét nhận được: \(jsonString)") } }.resume()
Dart (Flutter)
// Flutter / Dart http package import 'package:http/http.dart' as http; import 'dart:convert'; Future<void> fetchLightning() async { final url = Uri.parse('https://evntools.com/api/v1/lightning/radius?lat=21.0285&lon=105.854&radius=50&hours=1'); final response = await http.get(url, headers: { 'X-API-Key': 'evn_your_api_key_here', }); if (response.statusCode == 200) { final data = jsonDecode(response.body); print('Tổng số sét trong 50km: ${data["count"]}'); } }
ESP32 (Arduino C++)
// ESP32 IoT: Kích hoạt còi báo động khi có sét gần trạm #include <WiFi.h> #include <HTTPClient.h> void checkLightningAlert() { HTTPClient http; http.begin("https://evntools.com/api/v1/lightning/radius?lat=20.254&lon=105.975&radius=15&hours=1"); http.addHeader("X-API-Key", "evn_your_api_key_here"); int httpCode = http.GET(); if (httpCode == 200) { String payload = http.getString(); // Nếu count > 0 -> Bật còi cảnh báo if (payload.indexOf("\"count\":0") < 0) { digitalWrite(2, HIGH); // Bật còi / đèn } } http.end(); }

🔌 API Endpoints

GET /api/v1/lightning Lấy dữ liệu sét theo thời gian & nguồn

Trả về danh sách các tia sét trong khoảng thời gian yêu cầu (sắp xếp mới nhất trước). Giới hạn tối đa theo gói cước: 2,000 bản ghi (Test/Premium), 5,000 bản ghi (Enterprise).

Query Parameters

Tham sốKiểuBắt buộcMô tả
sourcestringKhôngNguồn dữ liệu: all (Tất cả nguồn), m (Nguồn M), v (Nguồn V), w (Nguồn W), h (Nguồn H). Mặc định: all
hoursintegerKhôngSố giờ lịch sử tra cứu (1–720). Mặc định: 1. Giới hạn tối đa tùy theo gói cước.

Request ví dụ

HTTP Request
GET /api/v1/lightning?source=all&hours=2 HTTP/1.1 Host: evntools.com X-API-Key: evn_your_api_key_here

Response (200 OK)

JSON
{ "status": "success", "count": 3, "data": [ { "id": 198234, "time": "2024-06-13T15:42:07", "lat": 21.0285, "lon": 105.854, "source": "M", "type": "CG", "amplitude": -34.7 }, ... ]}
GET /api/v1/lightning/radius Lấy sét trong bán kính từ 1 điểm tâm (Tối đa 100 km)

Lấy tất cả tia sét xuất hiện trong bán kính X km (từ 1 đến 100 km) tính từ 1 điểm toạ độ trung tâm. Giới hạn tối đa theo gói cước: 500 bản ghi (Free/Basic), 2,000 bản ghi (Test/Premium), 5,000 bản ghi (Enterprise).

💡
Response tự động tính trường distance_km — khoảng cách từ tâm đến tia sét theo công thức Haversine, đã sắp xếp gần → xa.

Query Parameters

Tham sốKiểuBắt buộcMô tả
latfloatCóVĩ độ trung tâm. Ví dụ: 21.0285
lonfloatCóKinh độ trung tâm. Ví dụ: 105.854
radiusfloatKhôngBán kính tìm kiếm (km). Mặc định: 50. Tối đa: 100 km.
hoursintegerKhôngSố giờ lịch sử (1–720). Mặc định: 1. Giới hạn tối đa tùy theo gói cước.
sourcestringKhôngNguồn dữ liệu: all (Tất cả nguồn), m, v, w, h. Mặc định: all

Request ví dụ — Giám sát 50km quanh Hà Nội

cURL
curl -X GET "https://evntools.com/api/v1/lightning/radius?lat=21.0285&lon=105.854&radius=50&hours=1&source=all" \ -H "X-API-Key: evn_your_api_key_here"
Python
import requests resp = requests.get( "https://evntools.com/api/v1/lightning/radius", params={ "lat": 21.0285, # Tâm: Hà Nội "lon": 105.854, "radius": 50, # Bán kính 50 km "hours": 1, "source": "all" }, headers={"X-API-Key": "evn_your_api_key_here"} ) data = resp.json() print(f"Có {data['count']} tia sét trong bán kính 50km") for b in data["data"]: print(f" {b['distance_km']:.1f}km | {b['time']} | {b.get('amplitude','?')} kA")
JavaScript
const res = await fetch( `https://evntools.com/api/v1/lightning/radius?lat=21.0285&lon=105.854&radius=50&hours=1`, { headers: { 'X-API-Key': 'evn_your_api_key_here' } } ); const { data } = await res.json(); data.forEach(b => console.log(`${b.distance_km.toFixed(1)}km away | ${b.amplitude} kA`));

Response (200 OK)

JSON
{ "status": "success", "count": 2, "center": { "lat": 21.0285, "lon": 105.854 }, "radius_km": 50, "data": [ { "id": 198234, "time": "2024-06-13T15:42:07", "lat": 21.15, "lon": 105.92, "amplitude": -34.7, "type": "CG", "distance_km": 18.3 // khoảng cách từ tâm }, { "id": 198301, "time": "2024-06-13T15:38:21", "lat": 20.85, "lon": 106.20, "amplitude": -12.1, "type": "CG", "distance_km": 43.7 } ] }

📋 Giải thích các trường dữ liệu

TrườngKiểu dữ liệuMô tả
idintegerID duy nhất của tia sét trong hệ thống
timestring (ISO)Thời điểm xảy ra sét (UTC). Format: 2024-06-13T15:42:07.123000
latfloatVĩ độ (latitude). Phạm vi: -90 đến 90
lonfloatKinh độ (longitude). Phạm vi: -180 đến 180
sourcestringKý hiệu nguồn dữ liệu: M (Nguồn M), V (Nguồn V), W (Nguồn W), H (Nguồn H)
typestringLoại sét: CG (Cloud-to-Ground — sét đánh xuống đất), CC (Cloud-to-Cloud — sét trong mây). Gói Basic+
amplitudefloat (kA)Cường độ dòng điện (kiloAmpe). Âm = sét xuống đất, dương = sét lên trời. Gói Basic+
altitudefloat (m)Độ cao của tia sét (mét). Gói Enterprise+
polarizationintegerPhân cực (0, 1). Gói Enterprise+
accuracyfloat (km)Bán kính sai số vị trí (km). Càng nhỏ càng chính xác. Gói Enterprise+

Các trường có gói Basic+ chỉ xuất hiện khi gói cước của bạn cho phép. Với gói Free chúng sẽ không có trong response.

❌ Mã lỗi HTTP

StatusCode lỗiNguyên nhân & Cách xử lý
401 API Key is missing Không có header X-API-Key. Thêm header vào request.
403 Invalid API Key Key sai hoặc không tồn tại. Kiểm tra lại key trong trang "API Keys của tôi".
403 pending approval Key chưa được Admin duyệt. Vui lòng chờ.
403 API Key has expired Key hết hạn. Liên hệ Admin để gia hạn hoặc đổi gói.
403 IP address not allowed IP của bạn không nằm trong whitelist của key. Đăng ký lại key hoặc bỏ giới hạn IP.
403 plan does not allow source Gói cước không hỗ trợ nguồn dữ liệu đó. Dùng nguồn khác hoặc nâng gói.
429 Rate limit exceeded Vượt giới hạn request/phút. Giảm tốc độ gọi, thêm delay giữa các request.
429 Daily quota exceeded Hết quota ngày. Reset lúc 00:00 UTC. Nâng gói để tăng quota.
500 Plan configuration missing Lỗi hệ thống nội bộ. Liên hệ Admin.

💻 Ví dụ Code chi tiết

Hiển thị sét lên bản đồ Leaflet (JavaScript)

JavaScript + Leaflet.js
// Cần nhúng Leaflet.js trước: https://leafletjs.com const API_KEY = 'evn_your_api_key_here'; // Khởi tạo bản đồ Việt Nam const map = L.map('map').setView([16.0, 108.0], 6); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map); async function loadLightning() { const res = await fetch(`https://evntools.com/api/v1/lightning?source=all&hours=1`, { headers: { 'X-API-Key': API_KEY } }); const { data } = await res.json(); data.forEach(bolt => { const color = bolt.amplitude > 0 ? '#f59e0b' : '#6366f1'; // Vàng/Tím L.circleMarker([bolt.lat, bolt.lon], { radius: 5, color: color, fillColor: color, fillOpacity: 0.8 }).bindPopup( `⚡ ${bolt.amplitude || '?'} kA | ${new Date(bolt.time).toLocaleString('vi-VN')}` ).addTo(map); }); } // Tự động cập nhật mỗi 60 giây loadLightning(); setInterval(loadLightning, 60000);

Lọc sét trong bán kính địa lý (Python)

Python
import requests, math def haversine(lat1, lon1, lat2, lon2): """Tính khoảng cách giữa 2 điểm (km)""" R = 6371 dlat = math.radians(lat2 - lat1) dlon = math.radians(lon2 - lon1) a = math.sin(dlat/2)**2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon/2)**2 return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) # Trạm điện: Ninh Bình STATION_LAT, STATION_LON = 20.254, 105.975 ALERT_RADIUS_KM = 30 # Cảnh báo nếu sét trong bán kính 30km resp = requests.get( "https://evntools.com/api/v1/lightning", params={"source": "all", "hours": 1}, headers={"X-API-Key": "evn_your_api_key_here"} ) bolts = resp.json()["data"] # Lọc sét gần trạm nearby = [ b for b in bolts if haversine(STATION_LAT, STATION_LON, b["lat"], b["lon"]) <= ALERT_RADIUS_KM ] print(f"⚠️ {len(nearby)} tia sét trong bán kính {ALERT_RADIUS_KM}km quanh trạm!") for b in nearby: print(f" → {b['time']} | {haversine(STATION_LAT,STATION_LON,b['lat'],b['lon']):.1f}km | {b.get('amplitude','?')} kA")

📧 Cần hỗ trợ? Liên hệ Admin qua evntools.com → Tab Liên hệ.

🔑 Chưa có API Key? Đăng ký tại đây (Gói Test kích hoạt ngay!)