diff --git a/extra_script.py b/extra_script.py index d430c30..7778c53 100644 --- a/extra_script.py +++ b/extra_script.py @@ -4,13 +4,18 @@ import shutil import os import sys import inspect +import json GEN_DIR='generated' -FILES=['web/index.html'] +CFG_FILE='web/config.json' +FILES=['web/index.html',CFG_FILE] +CFG_INCLUDE='GwConfigDefinitions.h' + +def basePath(): + #see: https://stackoverflow.com/questions/16771894/python-nameerror-global-name-file-is-not-defined + return os.path.dirname(inspect.getfile(lambda: None)) def outPath(): - #see: https://stackoverflow.com/questions/16771894/python-nameerror-global-name-file-is-not-defined - return os.path.join(os.path.dirname(inspect.getfile(lambda: None)),GEN_DIR) - + return os.path.join(basePath(),GEN_DIR) def checkDir(): dn=outPath() if not os.path.exists(dn): @@ -20,21 +25,59 @@ def checkDir(): return False return True -def compressFile(inFile): - outfile=os.path.basename(inFile)+".gz" - outfile=os.path.join(outPath(),outfile) +def isCurrent(infile,outfile): if os.path.exists(outfile): otime=os.path.getmtime(outfile) - itime=os.path.getmtime(inFile) + itime=os.path.getmtime(infile) if (otime >= itime): - print("%s is newer then %s, no need to recreate"%(outfile,inFile)) - return + print("%s is newer then %s, no need to recreate"%(outfile,infile)) + return True + return False +def compressFile(inFile): + outfile=os.path.basename(inFile)+".gz" + inFile=os.path.join(basePath(),inFile) + outfile=os.path.join(outPath(),outfile) + if isCurrent(inFile,outfile): + return with open(inFile, 'rb') as f_in: with gzip.open(outfile, 'wb') as f_out: shutil.copyfileobj(f_in, f_out) + +def generateCfg(): + outfile=os.path.join(outPath(),CFG_INCLUDE) + infile=os.path.join(basePath(),CFG_FILE) + if isCurrent(infile,outfile): + return + print("creating %s"%CFG_INCLUDE) + with open(CFG_FILE,'rb') as ch: + config=json.load(ch) + with open(outfile,'w') as oh: + oh.write("//generated from %s\n"%CFG_FILE) + oh.write('#include "GwConfigItem.h"\n') + l=len(config) + oh.write('class GwConfigDefinitions{\n') + oh.write(' public:\n') + oh.write(' int getNumConfig() const{return %d;}\n'%(l)) + for item in config: + n=item.get('name') + if n is None: + continue + oh.write(' const String %s=F("%s");\n'%(n,n)) + oh.write(' protected:\n') + oh.write(' GwConfigItem *configs[%d]={\n'%(l)) + first=True + for item in config: + if not first: + oh.write(',\n') + first=False + oh.write(" new GwConfigItem(%s,\"%s\")"%(item.get('name'),item.get('default'))) + oh.write('};\n') + oh.write('};\n') + oh.close() if not checkDir(): sys.exit(1) for f in FILES: print("compressing %s"%f) - compressFile(f) \ No newline at end of file + compressFile(f) +generateCfg() \ No newline at end of file diff --git a/lib/config/GWConfig.cpp b/lib/config/GWConfig.cpp index c2910f4..44078d6 100644 --- a/lib/config/GWConfig.cpp +++ b/lib/config/GWConfig.cpp @@ -54,7 +54,7 @@ GwConfigInterface * GwConfigHandler::getConfigItem(const String name, bool dummy return &dummyConfig; } #define PREF_NAME "gwprefs" -GwConfigHandler::GwConfigHandler(GwLog *logger){ +GwConfigHandler::GwConfigHandler(GwLog *logger): GwConfigDefinitions(){ this->logger=logger; } bool GwConfigHandler::loadConfig(){ diff --git a/lib/config/GWConfig.h b/lib/config/GWConfig.h index 9ea7d1b..8f8137f 100644 --- a/lib/config/GWConfig.h +++ b/lib/config/GWConfig.h @@ -3,74 +3,16 @@ #include #include #include "GwLog.h" - -class GwConfigInterface{ - public: - virtual String asString() const=0; - virtual const char * asCString() const =0; - virtual bool asBoolean() const = 0; - virtual int asInt() const = 0; -}; -class GwConfigItem: public GwConfigInterface{ - private: - String name; - String initialValue; - String value; - public: - GwConfigItem(const String &name, const String initialValue){ - this->name=name; - this->initialValue=initialValue; - this->value=initialValue; - } - virtual String asString() const{ - return value; - } - virtual const char * asCString() const{ - return value.c_str(); - }; - virtual void fromString(const String v){ - value=v; - }; - virtual bool asBoolean() const{ - return strcasecmp(value.c_str(),"true") == 0; - } - virtual int asInt() const{ - return (int)value.toInt(); - } - String getName() const{ - return name; - } - virtual void reset(){ - value=initialValue; - } - bool changed() const{ - return value != initialValue; - } - String getDefault() const { - return initialValue; - } -}; +#include "GwConfigItem.h" +#include "GwConfigDefinitions.h" -class GwConfigHandler{ +class GwConfigHandler: public GwConfigDefinitions{ private: Preferences prefs; GwLog *logger; public: public: - const String sendUsb=F("sendUsb"); - const String receiveUsb=F("receiveUsb"); - const String wifiClient=F("wifiClient"); - const String wifiPass=F("wifiPass"); - const String wifiSSID=F("wifiSSID"); - const String serverPort=F("serverPort"); - const String maxClients=F("maxClients"); - const String sendTCP=F("sendTCP"); - const String readTCP=F("receiveTCP"); - const String sendSeasmart=F("sendSeasmart"); - const String usbBaud=F("usbBaud"); - const String systemName=F("systemName"); - const String stopApTime=F("stopApTime"); GwConfigHandler(GwLog *logger); bool loadConfig(); bool saveConfig(); @@ -85,23 +27,5 @@ class GwConfigHandler{ GwConfigItem * findConfig(const String name, bool dummy=false); GwConfigInterface * getConfigItem(const String name, bool dummy=false) const; private: - GwConfigItem* configs[13]={ - new GwConfigItem(sendUsb,"true"), - new GwConfigItem (receiveUsb,"false"), - new GwConfigItem (wifiClient,"false"), - new GwConfigItem (wifiSSID,""), - new GwConfigItem (wifiPass,""), - new GwConfigItem (serverPort,"2222"), - new GwConfigItem (maxClients, "10"), - new GwConfigItem (sendTCP,"true"), - new GwConfigItem (readTCP,"true"), - new GwConfigItem (sendSeasmart,"false"), - new GwConfigItem (usbBaud,"115200"), - new GwConfigItem (systemName,"ESP32NMEA2K"), - new GwConfigItem (stopApTime,"0") - }; - int getNumConfig() const{ - return 13; - } }; #endif \ No newline at end of file diff --git a/lib/config/GwConfigItem.h b/lib/config/GwConfigItem.h new file mode 100644 index 0000000..528a1ce --- /dev/null +++ b/lib/config/GwConfigItem.h @@ -0,0 +1,52 @@ +#ifndef _GWCONFIGITEM_H +#define _GWCONFIGITEM_H +#include "WString.h" +class GwConfigInterface{ + public: + virtual String asString() const=0; + virtual const char * asCString() const =0; + virtual bool asBoolean() const = 0; + virtual int asInt() const = 0; +}; +class GwConfigItem: public GwConfigInterface{ + private: + String name; + String initialValue; + String value; + public: + GwConfigItem(const String &name, const String initialValue){ + this->name=name; + this->initialValue=initialValue; + this->value=initialValue; + } + virtual String asString() const{ + return value; + } + virtual const char * asCString() const{ + return value.c_str(); + }; + virtual void fromString(const String v){ + value=v; + }; + virtual bool asBoolean() const{ + return strcasecmp(value.c_str(),"true") == 0; + } + virtual int asInt() const{ + return (int)value.toInt(); + } + String getName() const{ + return name; + } + virtual void reset(){ + value=initialValue; + } + bool changed() const{ + return value != initialValue; + } + String getDefault() const { + return initialValue; + } +}; + + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 9e8c230..e1f3321 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,6 +19,7 @@ lib_deps = ottowinter/ESPAsyncWebServer-esphome@^2.0.1 board_build.embed_files = generated/index.html.gz + generated/config.json.gz extra_scripts = extra_script.py build_flags= -Igenerated diff --git a/src/main.cpp b/src/main.cpp index ba7039c..5861af5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,7 +12,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#define VERSION "0.1.1" +#define VERSION "0.1.2" #include "GwHardware.h" #include @@ -154,6 +154,7 @@ class EmbeddedFile { const EmbeddedFile fileName##_##fileExt##_Config(#fileName "." #fileExt,(const uint8_t*)fileName##_##fileExt##_File,(int)fileName##_##fileExt##_FileLen); EMBED_GZ_FILE(index,html) +EMBED_GZ_FILE(config,json) void sendEmbeddedFile(String name,String contentType,AsyncWebServerRequest *request){ std::map::iterator it=embeddedFiles.find(name); diff --git a/web/config.json b/web/config.json new file mode 100644 index 0000000..bd852ac --- /dev/null +++ b/web/config.json @@ -0,0 +1,99 @@ +[ + { + "name": "systemName", + "label": "system name", + "type": "string", + "default": "ESP32NMEA2K", + "check": "checkSystemName", + "description": "system name, used for the access point and for services" + }, + { + "name": "usbBaud", + "label": "USB baud rate", + "type": "list", + "default": "115200", + "description": "baud rate for the USB port", + "list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800] + }, + { + "name": "sendUsb", + "label": "NMEA to USB", + "type": "boolean", + "default": "true", + "description": "send out NMEA data on the USB port" + }, + { + "name": "receiveUsb", + "label": "NMEA from USB", + "type": "boolean", + "default": "true", + "description": "receive NMEA data on the USB port" + }, + { + "name": "serverPort", + "label": "TCP port", + "type": "number", + "default": "2222", + "description": "the TCP port we listen on" + }, + { + "name": "maxClients", + "label": "max. TCP clients", + "type": "number", + "default": "10", + "check":"checkMaxClients", + "description": "the number of clients we allow to connect to us" + }, + { + "name": "sendTCP", + "label": "NMEA to TCP", + "type": "boolean", + "default": "true", + "description": "send out NMEA data to connected TCP clients" + }, + { + "name": "readTCP", + "label": "NMEA from TCP", + "type": "boolean", + "default": "true", + "description": "receive NMEA data from connected TCP clients" + }, + { + "name": "sendSeasmart", + "label": "Seasmart to TCP", + "type": "boolean", + "default": "false", + "description": "send NMEA2000 as seasmart to connected TCP clients" + }, + { + "name": "wifiClient", + "label": "wifi client", + "type": "boolean", + "default": "false", + "description": "connect to an external WIFI network" + }, + { + "name": "wifiPass", + "label": "wifi client password", + "type": "password", + "default": "", + "description": "the password for an external WIFI network" + }, + { + "name": "wifiSSID", + "label": "wifi client SSID", + "type": "string", + "default": "", + "check": "checkSSID", + "description": "the SSID for an external WIFI network" + }, + { + "name": "stopApTime", + "type": "number", + "default": "0", + "check": "checkStopApTime", + "description": "stop the access point after that many minutes if not used" + } + + +] \ No newline at end of file