From d0256fd37cab52e7195c69b945a1834fe7e18a20 Mon Sep 17 00:00:00 2001 From: free-x Date: Mon, 24 Feb 2025 19:01:13 +0100 Subject: [PATCH 1/6] #103: Initial VWR --- lib/nmea2kto0183/N2kDataToNMEA0183.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 1056c87..11854f1 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -528,6 +528,30 @@ private: { SendMessage(NMEA0183Msg); } + + if (shouldSend && NMEA0183Reference == NMEA0183Wind_Apparent) + { + if (!NMEA0183Msg.Init("VWR", talkerId)) + return; + if (!NMEA0183Msg.AddUInt32Field((abs(WindAngle) > 180 ) ? 360-abs(WindAngle) : abs(WindAngle) )) + return; + if (!NMEA0183Msg.AddStrField((WindAngle >= 0 && WindAngle <= 180) ? 'R' : 'L')) + return; + if (!NMEA0183Msg.AddDoubleField(WindSpeed * 3600.0/1852.0)) + return; + if (!NMEA0183Msg.AddStrField("N")) + return; + if (!NMEA0183Msg.AddDoubleField(WindSpeed)) + return; + if (!NMEA0183Msg.AddStrField("M")) + return; + if (!NMEA0183Msg.AddDoubleField(WindSpeed * 3600.0/1000.0)) + return; + if (!NMEA0183Msg.AddStrField("K")) + return; + + SendMessage(NMEA0183Msg); + } } /* if (WindReference == N2kWind_Apparent && boatData->SOG->isValid()) From 6a2c623ea03c387595c6a6348034e28193acee04 Mon Sep 17 00:00:00 2001 From: free-x Date: Tue, 25 Feb 2025 18:54:00 +0100 Subject: [PATCH 2/6] #103: using formatters --- lib/boatData/GwBoatData.cpp | 7 ++++++- lib/boatData/GwBoatData.h | 3 ++- lib/nmea2kto0183/N2kDataToNMEA0183.cpp | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index 39d22c8..424ebe4 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -493,6 +493,11 @@ double formatKnots(double cv) return cv * 3600.0 / 1852.0; } +double formatKmh(double cv) +{ + return cv *3600.0 / 1000.0; +} + uint32_t mtr2nm(uint32_t m) { return m / 1852; @@ -523,4 +528,4 @@ public: }; static XWriter xwriter; ARDUINOJSON_NAMESPACE::TextFormatter testWriter(xwriter); -#endif \ No newline at end of file +#endif diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index a4df3b4..ae50b3f 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -129,6 +129,7 @@ double formatCourse(double cv); double formatDegToRad(double deg); double formatWind(double cv); double formatKnots(double cv); +double formatKmh(double cv); uint32_t mtr2nm(uint32_t m); double mtr2nm(double m); @@ -251,4 +252,4 @@ class GwBoatData{ }; -#endif \ No newline at end of file +#endif diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 11854f1..278c71e 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -537,7 +537,7 @@ private: return; if (!NMEA0183Msg.AddStrField((WindAngle >= 0 && WindAngle <= 180) ? 'R' : 'L')) return; - if (!NMEA0183Msg.AddDoubleField(WindSpeed * 3600.0/1852.0)) + if (!NMEA0183Msg.AddDoubleField(formatKnots(WindSpeed))) return; if (!NMEA0183Msg.AddStrField("N")) return; @@ -545,7 +545,7 @@ private: return; if (!NMEA0183Msg.AddStrField("M")) return; - if (!NMEA0183Msg.AddDoubleField(WindSpeed * 3600.0/1000.0)) + if (!NMEA0183Msg.AddDoubleField(formatKmh(WindSpeed))) return; if (!NMEA0183Msg.AddStrField("K")) return; From 5e41c64dd39e74a20fd5e9f38d9bb55270f806ba Mon Sep 17 00:00:00 2001 From: free-x Date: Thu, 27 Feb 2025 19:44:19 +0100 Subject: [PATCH 3/6] #103: fix units logic --- lib/nmea2kto0183/N2kDataToNMEA0183.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 278c71e..afafcd6 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -531,11 +531,12 @@ private: if (shouldSend && NMEA0183Reference == NMEA0183Wind_Apparent) { + double wa = formatCourse(WindAngle); if (!NMEA0183Msg.Init("VWR", talkerId)) return; - if (!NMEA0183Msg.AddUInt32Field((abs(WindAngle) > 180 ) ? 360-abs(WindAngle) : abs(WindAngle) )) + if (!NMEA0183Msg.AddDoubleField(( wa > 180 ) ? 360-wa : wa)) return; - if (!NMEA0183Msg.AddStrField((WindAngle >= 0 && WindAngle <= 180) ? 'R' : 'L')) + if (!NMEA0183Msg.AddStrField(( wa >= 0 && wa <= 180) ? 'R' : 'L')) return; if (!NMEA0183Msg.AddDoubleField(formatKnots(WindSpeed))) return; From 2ab6a00883b123b1ef539d929fb4585dc6f78df6 Mon Sep 17 00:00:00 2001 From: andreas Date: Tue, 4 Mar 2025 20:47:47 +0100 Subject: [PATCH 4/6] #102: only reconnect wifi every 40s --- lib/gwwifi/GwWifi.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gwwifi/GwWifi.cpp b/lib/gwwifi/GwWifi.cpp index 6cd7f72..c81acec 100644 --- a/lib/gwwifi/GwWifi.cpp +++ b/lib/gwwifi/GwWifi.cpp @@ -85,6 +85,7 @@ bool GwWifi::connectInternal(){ if (wifiClient->asBoolean()){ clientIsConnected=false; LOG_DEBUG(GwLog::LOG,"creating wifiClient ssid=%s",wifiSSID->asString().c_str()); + WiFi.setAutoReconnect(false); //#102 wl_status_t rt=WiFi.begin(wifiSSID->asCString(),wifiPass->asCString()); LOG_DEBUG(GwLog::LOG,"wifiClient connect returns %d",(int)rt); lastConnectStart=millis(); @@ -92,7 +93,8 @@ bool GwWifi::connectInternal(){ } return false; } -#define RETRY_MILLIS 20000 +//#102: we should have a wifi connect retry being > 30s - with some headroom +#define RETRY_MILLIS 40000 void GwWifi::loop(){ if (wifiClient->asBoolean()) { From 437b76897aa9ae0355140d09deb60080975005c9 Mon Sep 17 00:00:00 2001 From: andreas Date: Tue, 4 Mar 2025 20:48:02 +0100 Subject: [PATCH 5/6] #101: avoid logging errors for all unset config items --- lib/config/GWConfig.cpp | 26 +++++++++++++++----------- lib/config/GWConfig.h | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/config/GWConfig.cpp b/lib/config/GWConfig.cpp index b372d3d..692b58a 100644 --- a/lib/config/GWConfig.cpp +++ b/lib/config/GWConfig.cpp @@ -27,18 +27,19 @@ class DummyConfig : public GwConfigInterface{ }; DummyConfig dummyConfig; -String GwConfigHandler::toString() const{ - String rt; - rt+="Config: "; - for (int i=0;igetName(); - rt+="="; - rt+=configs[i]->asString(); - rt+=", "; - } - return rt; +void GwConfigHandler::logConfig(int level) const +{ + if (!logger->isActive(level)) + return; + for (int i = 0; i < getNumConfig(); i++) + { + String v=configs[i]->asString(); + bool isChanged=v != configs[i]->getDefault(); + logger->logDebug(level, "Config[%s]%s='%s'", configs[i]->getName().c_str(),isChanged?"*":"", configs[i]->isSecret() ? "***" : configs[i]->asString().c_str()); + if ((i%20) == 19) logger->flush(); } - + logger->flush(); +} String GwConfigHandler::toJson() const{ String rt; int num=getNumConfig(); @@ -80,6 +81,9 @@ GwConfigHandler::~GwConfigHandler(){ bool GwConfigHandler::loadConfig(){ prefs->begin(PREF_NAME,true); for (int i=0;iisKey(configs[i]->getName().c_str())) { + continue; + } String v=prefs->getString(configs[i]->getName().c_str(),configs[i]->getDefault()); configs[i]->value=v; } diff --git a/lib/config/GWConfig.h b/lib/config/GWConfig.h index eb2a095..1f50ca3 100644 --- a/lib/config/GWConfig.h +++ b/lib/config/GWConfig.h @@ -22,7 +22,7 @@ class GwConfigHandler: public GwConfigDefinitions{ void stopChanges(); bool updateValue(String name, String value); bool reset(); - String toString() const; + void logConfig(int level) const; String toJson() const; String getString(const String name,const String defaultv="") const; bool getBool(const String name,bool defaultv=false) const ; From a1b8f069592d5c0acab75b334d1eb5ad02826901 Mon Sep 17 00:00:00 2001 From: andreas Date: Tue, 4 Mar 2025 20:48:12 +0100 Subject: [PATCH 6/6] #101: avoid logging errors for all unset config items --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index c12f906..4dff162 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -801,6 +801,7 @@ void setup() { MDNS.begin(config.getConfigItem(config.systemName)->asCString()); channels.begin(fallbackSerial); logger.flush(); + config.logConfig(GwLog::DEBUG); webserver.registerMainHandler("/api/reset", [](AsyncWebServerRequest *request)->GwRequestMessage *{ return new ResetRequest(request->arg("_hash")); });