intermediate: externalize config definitions
This commit is contained in:
parent
b5aa62ff49
commit
b4fe48744b
|
@ -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)
|
||||
compressFile(f)
|
||||
generateCfg()
|
|
@ -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(){
|
||||
|
|
|
@ -3,74 +3,16 @@
|
|||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 <Arduino.h>
|
||||
|
@ -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<String,EmbeddedFile*>::iterator it=embeddedFiles.find(name);
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
]
|
Loading…
Reference in New Issue