65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2024 年 5 月 9 日

CPOL
viewsIcon

13503

使用 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 日 - 首次提交
© . All rights reserved.