使用 ESP32 和 Arduino 进行 IP 地理位置定位





5.00/5 (3投票s)
使用 ESP32 和 ip-api.com 根据您的 IP 地址获取位置信息
引言
我曾在几个项目中用到过这个方法,但一直没有详细讨论过,而且我已经改进了代码。它至少值得一篇独立的教程。
如果没有 GPS,如何获取时区?NTP 服务不提供时区信息。答案是 IP 地理位置定位,而 http://ip-api.com 非常适合这个任务。
必备组件
- 你需要安装了 PlatformIO 的 VS Code
- 你需要一个 ESP32
使用代码
该 API 使用起来很简单。在使用它之前,你需要连接 WiFi。
将以下库添加到你的项目中:codewitch-honey-crisis/htcw_json
将这些文件复制到你的项目中
ip_loc.hpp
#pragma once
#ifndef ESP32
#error "This library only supports the ESP32 MCU."
#endif
#include <Arduino.h>
namespace arduino {
struct ip_loc final {
static bool fetch(float* out_lat,
float* out_lon,
long* out_utc_offset,
char* out_region,
size_t region_size,
char* out_city,
size_t city_size,
char* out_time_zone,
size_t time_zone_size);
};
}
ip_loc.cpp
#ifdef ESP32
#include <ip_loc.hpp>
#include <HTTPClient.h>
#include <json.hpp>
namespace arduino {
static char* ip_loc_fetch_replace_char(char* str, char find, char replace){
char *current_pos = strchr(str,find);
while (current_pos) {
*current_pos = replace;
current_pos = strchr(current_pos+1,find);
}
return str;
}
bool ip_loc::fetch(float* out_lat,
float* out_lon,
long* out_utc_offset,
char* out_region,
size_t region_size,
char* out_city,
size_t city_size,
char* out_time_zone,
size_t time_zone_size) {
// URL for IP resolution service
char url[256];
*url = 0;
strcpy(url,"http://ip-api.com/json/?fields=status");//,region,city,lat,lon,timezone,offset";
int count = 0;
if(out_lat!=nullptr) {
*out_lat = 0.0f;
strcat(url,",lat");
++count;
}
if(out_lon!=nullptr) {
*out_lon = 0.0f;
strcat(url,",lon");
++count;
}
if(out_utc_offset!=nullptr) {
*out_utc_offset = 0;
strcat(url,",offset");
++count;
}
if(out_region!=nullptr && region_size>0) {
*out_region = 0;
strcat(url,",region");
++count;
}
if(out_city!=nullptr && city_size>0) {
*out_city = 0;
strcat(url,",city");
++count;
}
if(out_time_zone!=nullptr && time_zone_size>0) {
*out_time_zone = 0;
strcat(url,",timezone");
++count;
}
HTTPClient client;
client.begin(url);
if(0>=client.GET()) {
return false;
}
Stream& stm = client.getStream();
io::arduino_stream astm(&stm);
json::json_reader_ex<512> reader(astm);
while(reader.read()) {
if(reader.depth()==1 && reader.node_type()==json::json_node_type::field) {
if(out_lat!=nullptr && 0==strcmp("lat",reader.value())) {
reader.read();
*out_lat = reader.value_real();
--count;
} else if(out_lon!=nullptr && 0==strcmp("lon",reader.value())) {
reader.read();
*out_lon = reader.value_real();
--count;
} else if(out_utc_offset!=nullptr && 0==strcmp("offset",reader.value())) {
reader.read();
*out_utc_offset = reader.value_int();
--count;
} else if(out_region!=nullptr && region_size>0 && 0==strcmp("region",reader.value())) {
reader.read();
strncpy(out_region,reader.value(),region_size);
--count;
} else if(out_city!=nullptr && city_size > 0 && 0==strcmp("city",reader.value())) {
reader.read();
strncpy(out_city,reader.value(),city_size);
--count;
} else if(out_time_zone!=nullptr && time_zone_size>0 && 0==strcmp("timezone",reader.value())) {
reader.read();
strncpy(out_time_zone, reader.value(),time_zone_size);
ip_loc_fetch_replace_char(out_time_zone,'_',' ');
--count;
}
} else if(count<1 || reader.depth()==0) {
// don't wait for end of document to terminate the connection
break;
}
}
client.end();
return true;
}
}
#endif
要使用它,你可以调用 ip_loc::fetch()
,对于不需要的参数传递空值和零,但否则提供用于输出数据的缓冲区。字符串数据需要你告诉它缓冲区的大小。
#include <ip_loc.hpp>
...
long time_offset;
char time_zone_buffer[128];
...
// grabs the timezone and tz offset based on IP
arduino::ip_loc::fetch(
nullptr,
nullptr,
&time_offset,
nullptr,
0,
nullptr,
0,
time_zone_buffer,
sizeof(time_zone_buffer)
);
历史
- 2024 年 5 月 9 日 - 首次提交