intermediate: externalize config definitions
This commit is contained in:
parent
b5aa62ff49
commit
b4fe48744b
|
@ -4,13 +4,18 @@ import shutil
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
|
import json
|
||||||
GEN_DIR='generated'
|
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():
|
def outPath():
|
||||||
#see: https://stackoverflow.com/questions/16771894/python-nameerror-global-name-file-is-not-defined
|
return os.path.join(basePath(),GEN_DIR)
|
||||||
return os.path.join(os.path.dirname(inspect.getfile(lambda: None)),GEN_DIR)
|
|
||||||
|
|
||||||
def checkDir():
|
def checkDir():
|
||||||
dn=outPath()
|
dn=outPath()
|
||||||
if not os.path.exists(dn):
|
if not os.path.exists(dn):
|
||||||
|
@ -20,21 +25,59 @@ def checkDir():
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def compressFile(inFile):
|
def isCurrent(infile,outfile):
|
||||||
outfile=os.path.basename(inFile)+".gz"
|
|
||||||
outfile=os.path.join(outPath(),outfile)
|
|
||||||
if os.path.exists(outfile):
|
if os.path.exists(outfile):
|
||||||
otime=os.path.getmtime(outfile)
|
otime=os.path.getmtime(outfile)
|
||||||
itime=os.path.getmtime(inFile)
|
itime=os.path.getmtime(infile)
|
||||||
if (otime >= itime):
|
if (otime >= itime):
|
||||||
print("%s is newer then %s, no need to recreate"%(outfile,inFile))
|
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
|
return
|
||||||
with open(inFile, 'rb') as f_in:
|
with open(inFile, 'rb') as f_in:
|
||||||
with gzip.open(outfile, 'wb') as f_out:
|
with gzip.open(outfile, 'wb') as f_out:
|
||||||
shutil.copyfileobj(f_in, 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():
|
if not checkDir():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
for f in FILES:
|
for f in FILES:
|
||||||
print("compressing %s"%f)
|
print("compressing %s"%f)
|
||||||
compressFile(f)
|
compressFile(f)
|
||||||
|
generateCfg()
|
|
@ -54,7 +54,7 @@ GwConfigInterface * GwConfigHandler::getConfigItem(const String name, bool dummy
|
||||||
return &dummyConfig;
|
return &dummyConfig;
|
||||||
}
|
}
|
||||||
#define PREF_NAME "gwprefs"
|
#define PREF_NAME "gwprefs"
|
||||||
GwConfigHandler::GwConfigHandler(GwLog *logger){
|
GwConfigHandler::GwConfigHandler(GwLog *logger): GwConfigDefinitions(){
|
||||||
this->logger=logger;
|
this->logger=logger;
|
||||||
}
|
}
|
||||||
bool GwConfigHandler::loadConfig(){
|
bool GwConfigHandler::loadConfig(){
|
||||||
|
|
|
@ -3,74 +3,16 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include "GwLog.h"
|
#include "GwLog.h"
|
||||||
|
#include "GwConfigItem.h"
|
||||||
class GwConfigInterface{
|
#include "GwConfigDefinitions.h"
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class GwConfigHandler{
|
class GwConfigHandler: public GwConfigDefinitions{
|
||||||
private:
|
private:
|
||||||
Preferences prefs;
|
Preferences prefs;
|
||||||
GwLog *logger;
|
GwLog *logger;
|
||||||
public:
|
public:
|
||||||
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);
|
GwConfigHandler(GwLog *logger);
|
||||||
bool loadConfig();
|
bool loadConfig();
|
||||||
bool saveConfig();
|
bool saveConfig();
|
||||||
|
@ -85,23 +27,5 @@ class GwConfigHandler{
|
||||||
GwConfigItem * findConfig(const String name, bool dummy=false);
|
GwConfigItem * findConfig(const String name, bool dummy=false);
|
||||||
GwConfigInterface * getConfigItem(const String name, bool dummy=false) const;
|
GwConfigInterface * getConfigItem(const String name, bool dummy=false) const;
|
||||||
private:
|
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
|
#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
|
ottowinter/ESPAsyncWebServer-esphome@^2.0.1
|
||||||
board_build.embed_files =
|
board_build.embed_files =
|
||||||
generated/index.html.gz
|
generated/index.html.gz
|
||||||
|
generated/config.json.gz
|
||||||
extra_scripts = extra_script.py
|
extra_scripts = extra_script.py
|
||||||
build_flags=
|
build_flags=
|
||||||
-Igenerated
|
-Igenerated
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
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 "GwHardware.h"
|
||||||
|
|
||||||
#include <Arduino.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);
|
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(index,html)
|
||||||
|
EMBED_GZ_FILE(config,json)
|
||||||
|
|
||||||
void sendEmbeddedFile(String name,String contentType,AsyncWebServerRequest *request){
|
void sendEmbeddedFile(String name,String contentType,AsyncWebServerRequest *request){
|
||||||
std::map<String,EmbeddedFile*>::iterator it=embeddedFiles.find(name);
|
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