Original project changes: GPS: add normalized signal quality level, add web UI live status info

This commit is contained in:
Carsten Schmiemann 2022-05-03 00:18:10 +02:00
parent efb2404917
commit 84293ed725
7 changed files with 80 additions and 32 deletions

View file

@ -191,12 +191,28 @@ void GsmNMEA::IncomingLine(const std::string line)
*StdMetrics.ms_v_pos_gpsmode = (std::string) mode;
*StdMetrics.ms_v_pos_satcount = (int) satcnt;
*StdMetrics.ms_v_pos_gpshdop = (float) hdop;
// Derive signal quality from lock status, satellite count and HDOP:
// quality ~ satcnt / hdop
*StdMetrics.ms_v_pos_gpssq = (int) LIMIT_MAX(gpslock * LIMIT_MIN(satcnt-1,0) / LIMIT_MIN(hdop,0.1) * 10, 100);
// Quality raises by satellite count and drops by HDOP. HDOP 1.0 = perfect.
// The calculation is designed to get 50% as the threshold for a "good" signal.
// GPS needs at least 4 satellites in view to get a position, but that will need
// HDOP << 1 to be considered reliable. 6 satellites are on the edge to "good"
// (with HDOP=1). Samples:
// 4 satellites / HDOP 1.0 → SQ 30%
// 4 satellites / HDOP 0.6 → SQ 50%
// 6 satellites / HDOP 1.0 → SQ 50%
// 9 satellites / HDOP 1.0 → SQ 80%
// 10 satellites / HDOP 0.9 → SQ 100%
// 10 satellites / HDOP 1.8 → SQ 50%
if (gpslock)
{
*StdMetrics.ms_v_pos_latitude = (float) lat;
*StdMetrics.ms_v_pos_longitude = (float) lon;
*StdMetrics.ms_v_pos_altitude = (float) alt;
*StdMetrics.ms_v_pos_gpstime = (int) time(NULL);
}
// upodate gpslock last, so listeners will see updated lat/lon values:
@ -281,6 +297,12 @@ void GsmNMEA::Shutdown(bool hard)
{
ESP_LOGI(TAG, "Shutdown (direct)");
*StdMetrics.ms_v_pos_gpsmode = (std::string) "";
*StdMetrics.ms_v_pos_gpsspeed = (float) 0;
*StdMetrics.ms_v_pos_satcount = (int) 0;
*StdMetrics.ms_v_pos_gpshdop = (float) 500;
*StdMetrics.ms_v_pos_gpssq = (int) 0;
if (StdMetrics.ms_v_pos_gpslock->AsBool())
{
*StdMetrics.ms_v_pos_gpslock = (bool) false;

View file

@ -439,7 +439,10 @@ void location_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int ar
writer->printf("(%sGPS lock", MyLocations.m_gpslock ? "" : "without ");
n = StandardMetrics.ms_v_pos_satcount->AsInt();
if (n > 0)
writer->printf(", %d satellite%s", n, n == 1 ? "" : "s");
{
writer->printf(", %d satellite%s, %s", n, n == 1 ? "" : "s",
MyLocations.m_gpsgood ? "reliable" : "unreliable");
}
writer->puts(")");
if ((MyLocations.m_park_latitude != 0) || (MyLocations.m_park_longitude != 0))
@ -618,6 +621,8 @@ OvmsLocations::OvmsLocations()
m_ready = false;
m_gpslock = false;
m_gpssq = 0;
m_gpsgood = false;
m_latitude = 0;
m_longitude = 0;
m_park_latitude = 0;
@ -671,8 +676,8 @@ OvmsLocations::OvmsLocations()
using std::placeholders::_1;
using std::placeholders::_2;
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSLOCK, std::bind(&OvmsLocations::UpdatedGpsLock, this, _1));
MyMetrics.RegisterListener(TAG, MS_V_POS_LATITUDE, std::bind(&OvmsLocations::UpdatedLatitude, this, _1));
MyMetrics.RegisterListener(TAG, MS_V_POS_LONGITUDE, std::bind(&OvmsLocations::UpdatedLongitude, this, _1));
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSSQ, std::bind(&OvmsLocations::UpdatedGpsSQ, this, _1));
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSTIME, std::bind(&OvmsLocations::UpdatedPosition, this, _1));
MyMetrics.RegisterListener(TAG, MS_V_ENV_ON, std::bind(&OvmsLocations::UpdatedVehicleOn, this, _1));
MyEvents.RegisterEvent(TAG,"config.mounted", std::bind(&OvmsLocations::UpdatedConfig, this, _1, _2));
MyEvents.RegisterEvent(TAG,"config.changed", std::bind(&OvmsLocations::UpdatedConfig, this, _1, _2));
@ -696,12 +701,6 @@ void OvmsLocations::UpdatedGpsLock(OvmsMetric* metric)
m_gpslock = m->AsBool();
if (m_gpslock)
{
if (!m_ready)
{
UpdateParkPosition();
m_ready = true;
}
UpdateLocations();
MyEvents.SignalEvent("gps.lock.acquired", NULL);
}
else
@ -710,22 +709,36 @@ void OvmsLocations::UpdatedGpsLock(OvmsMetric* metric)
}
}
void OvmsLocations::UpdatedLatitude(OvmsMetric* metric)
void OvmsLocations::UpdatedGpsSQ(OvmsMetric* metric)
{
OvmsMetricFloat* m = (OvmsMetricFloat*)metric;
m_latitude = m->AsFloat();
if (m_gpslock)
m_gpssq = StdMetrics.ms_v_pos_gpssq->AsInt();
int level_good = MyConfig.GetParamValueInt("vehicle", "gps.sq.good", 60);
int level_bad = MyConfig.GetParamValueInt("vehicle", "gps.sq.bad", 40);
if (level_bad >= level_good) level_bad = level_good - 1;
if (!m_gpsgood && m_gpssq >= level_good)
{
m_gpsgood = true;
if (!m_ready)
{
UpdateParkPosition();
m_ready = true;
}
UpdateLocations();
CheckTheft();
MyEvents.SignalEvent("gps.sq.good", NULL);
}
else if (m_gpsgood && m_gpssq <= level_bad)
{
m_gpsgood = false;
MyEvents.SignalEvent("gps.sq.bad", NULL);
}
}
void OvmsLocations::UpdatedLongitude(OvmsMetric* metric)
void OvmsLocations::UpdatedPosition(OvmsMetric* metric)
{
OvmsMetricFloat* m = (OvmsMetricFloat*)metric;
m_longitude = m->AsFloat();
if (m_gpslock)
m_latitude = StdMetrics.ms_v_pos_latitude->AsFloat();
m_longitude = StdMetrics.ms_v_pos_longitude->AsFloat();
if (m_gpsgood)
{
UpdateLocations();
CheckTheft();
@ -753,13 +766,13 @@ void OvmsLocations::UpdateParkPosition()
{
m_park_latitude = m_latitude;
m_park_longitude = m_longitude;
m_park_invalid = (!m_gpslock || StdMetrics.ms_v_pos_latitude->IsStale() || StdMetrics.ms_v_pos_longitude->IsStale());
m_park_invalid = (!m_gpsgood || StdMetrics.ms_v_pos_latitude->IsStale() || StdMetrics.ms_v_pos_longitude->IsStale());
m_last_alarm = 0;
ESP_LOGI(TAG, "UpdateParkPosition: vehicle is parking @%0.6f,%0.6f gpslock=%d satcount=%d hdop=%.1f invalid=%d",
ESP_LOGI(TAG, "UpdateParkPosition: vehicle is parking @%0.6f,%0.6f gpslock=%d satcount=%d hdop=%.1f sq=%d invalid=%d",
m_park_latitude, m_park_longitude, m_gpslock,
StdMetrics.ms_v_pos_satcount->AsInt(),
StdMetrics.ms_v_pos_gpshdop->AsFloat(),
m_park_invalid);
m_gpssq, m_park_invalid);
}
}
@ -813,7 +826,7 @@ void OvmsLocations::ReloadMap()
}
}
if (m_gpslock) UpdateLocations();
if (m_gpsgood) UpdateLocations();
}
void OvmsLocations::UpdateLocations()

View file

@ -96,6 +96,8 @@ class OvmsLocations
public:
bool m_ready;
bool m_gpslock;
int m_gpssq;
bool m_gpsgood;
float m_latitude;
float m_longitude;
float m_park_latitude;
@ -113,8 +115,8 @@ class OvmsLocations
public:
void UpdatedGpsLock(OvmsMetric* metric);
void UpdatedLatitude(OvmsMetric* metric);
void UpdatedLongitude(OvmsMetric* metric);
void UpdatedGpsSQ(OvmsMetric* metric);
void UpdatedPosition(OvmsMetric* metric);
void UpdatedVehicleOn(OvmsMetric* metric);
void UpdatedConfig(std::string event, void* data);
};

View file

@ -1182,6 +1182,7 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
StandardMetrics.ms_v_pos_direction->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_altitude->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_gpslock->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_gpssq->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_gpsmode->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_gpshdop->IsModifiedAndClear(MyOvmsServerV2Modifier) |
StandardMetrics.ms_v_pos_satcount->IsModifiedAndClear(MyOvmsServerV2Modifier) |
@ -1198,10 +1199,7 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
if ((!always)&&(!modified)) return;
bool stale =
StandardMetrics.ms_v_pos_latitude->IsStale() ||
StandardMetrics.ms_v_pos_longitude->IsStale() ||
StandardMetrics.ms_v_pos_direction->IsStale() ||
StandardMetrics.ms_v_pos_altitude->IsStale();
StandardMetrics.ms_v_pos_gpstime->IsStale();
char drivemode[10];
sprintf(drivemode, "%x", StandardMetrics.ms_v_env_drivemode->AsInt());
@ -1244,6 +1242,8 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
<< StandardMetrics.ms_v_pos_gpshdop->AsString("0", Native, 1)
<< ","
<< StandardMetrics.ms_v_pos_gpsspeed->AsString("0", units_speed, 1)
<< ","
<< StandardMetrics.ms_v_pos_gpssq->AsInt()
;
Transmit(buffer.str().c_str());

View file

@ -101,6 +101,13 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
"<div class=\"metric number\" data-metric=\"m.net.sq\"><span class=\"value\">?</span><span class=\"unit\">dBm</span></div>"
"</td>"
"</tr>"
"<tr>"
"<th>GPS</th>"
"<td>"
"<div class=\"metric number\" data-metric=\"v.p.satcount\"><span class=\"value\">?</span><span class=\"unit\">Satellites</span></div>"
"<div class=\"metric number\" data-metric=\"v.p.gpssq\"><span class=\"value\">?</span><span class=\"unit\">%</span></div>"
"</td>"
"</tr>"
"<tr>"
"<th>Main battery</th>"
"<td>"
@ -137,7 +144,7 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
output = ExecuteCommand("stat");
c.printf("<samp class=\"monitor\" id=\"vehicle-status\" data-updcmd=\"stat\" data-events=\"vehicle.charge\">%s</samp>", _html(output));
output = ExecuteCommand("location status");
c.printf("<samp class=\"monitor\" data-updcmd=\"location status\" data-events=\"gps.lock|location\">%s</samp>", _html(output));
c.printf("<samp class=\"monitor\" data-updcmd=\"location status\" data-events=\"gps.lock|gps.sq|location\">%s</samp>", _html(output));
c.panel_end(
"<ul class=\"list-inline\">"
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#vehicle-cmdres\" data-cmd=\"charge start\">Start charge</button></li>"
@ -1399,7 +1406,6 @@ void OvmsWebServer::HandleCfgServerV2(PageEntry_t& p, PageContext_t& c)
c.input_text("Server", "server", server.c_str(), "Enter host name or IP address",
"<p>Public OVMS V2 servers:</p>"
"<ul>"
"<li><code>ovms-server.bit-cloud.de</code> <a href=\"https://ovms.bit-cloud.de/user/register\" target=\"_blank\">Registration</a></li>"
"<li><code>api.openvehicles.com</code> <a href=\"https://www.openvehicles.com/user/register\" target=\"_blank\">Registration</a></li>"
"<li><code>ovms.dexters-web.de</code> <a href=\"https://dexters-web.de/?action=NewAccount\" target=\"_blank\">Registration</a></li>"
"</ul>");
@ -2643,7 +2649,6 @@ void OvmsWebServer::HandleCfgFirmware(PageEntry_t& p, PageContext_t& c)
"<p>Automatic updates are normally only done if a wifi connection is available at the time. Before allowing updates via modem, be aware a single firmware image has a size of around 3 MB, which may lead to additional costs on your data plan.</p>");
c.print(
"<datalist id=\"server-list\">"
"<option value=\"https://ovms-ota.bit-cloud.de\">"
"<option value=\"https://api.openvehicles.com/firmware/ota\">"
"<option value=\"https://ovms.dexters-web.de/firmware/ota\">"
"</datalist>"
@ -2654,7 +2659,7 @@ void OvmsWebServer::HandleCfgFirmware(PageEntry_t& p, PageContext_t& c)
"</datalist>"
);
c.input_text("Update server", "server", server.c_str(), "Specify or select from list (clear to see all options)",
"<p>Default is <code>https://ovms-ota.bit-cloud.de</code>.</p>",
"<p>Default is <code>https://api.openvehicles.com/firmware/ota</code>.</p>",
"list=\"server-list\"");
c.input_text("Version tag", "tag", tag.c_str(), "Specify or select from list (clear to see all options)",
"<p>Default is <code>main</code> for standard releases. Use <code>eap</code> (early access program) for stable or <code>edge</code> for bleeding edge developer builds.</p>",

View file

@ -257,6 +257,8 @@ MetricsStandard::MetricsStandard()
ms_v_pos_gpsmode = new OvmsMetricString(MS_V_POS_GPSMODE, SM_STALE_MIN);
ms_v_pos_gpshdop = new OvmsMetricFloat(MS_V_POS_GPSHDOP, SM_STALE_MIN);
ms_v_pos_satcount= new OvmsMetricInt(MS_V_POS_SATCOUNT, SM_STALE_MIN);
ms_v_pos_gpssq = new OvmsMetricInt(MS_V_POS_GPSSQ, SM_STALE_MIN, Percentage);
ms_v_pos_gpstime = new OvmsMetricInt(MS_V_POS_GPSTIME, SM_STALE_MIN, Seconds);
ms_v_pos_latitude = new OvmsMetricFloat(MS_V_POS_LATITUDE, SM_STALE_MIN, Other, true);
ms_v_pos_longitude = new OvmsMetricFloat(MS_V_POS_LONGITUDE, SM_STALE_MIN, Other, true);
ms_v_pos_location = new OvmsMetricString(MS_V_POS_LOCATION, SM_STALE_MID);

View file

@ -230,6 +230,8 @@
#define MS_V_POS_GPSMODE "v.p.gpsmode"
#define MS_V_POS_GPSHDOP "v.p.gpshdop"
#define MS_V_POS_SATCOUNT "v.p.satcount"
#define MS_V_POS_GPSSQ "v.p.gpssq"
#define MS_V_POS_GPSTIME "v.p.gpstime"
#define MS_V_POS_LATITUDE "v.p.latitude"
#define MS_V_POS_LONGITUDE "v.p.longitude"
#define MS_V_POS_LOCATION "v.p.location"
@ -491,6 +493,8 @@ class MetricsStandard
OvmsMetricString* ms_v_pos_gpsmode; // <GPS><GLONASS>; N/A/D/E (None/Autonomous/Differential/Estimated)
OvmsMetricFloat* ms_v_pos_gpshdop; // Horizontal dilution of precision (smaller=better)
OvmsMetricInt* ms_v_pos_satcount;
OvmsMetricInt* ms_v_pos_gpssq; // GPS signal quality [%] (<30 unusable, >50 good, >80 excellent)
OvmsMetricInt* ms_v_pos_gpstime; // Time (UTC) of GPS coordinates [Seconds]
OvmsMetricFloat* ms_v_pos_latitude;
OvmsMetricFloat* ms_v_pos_longitude;
OvmsMetricString* ms_v_pos_location; // Name of current location if defined