diff --git a/ConfigGen/configGen.py b/ConfigGen/configGen.py new file mode 100644 index 0000000..449e2da --- /dev/null +++ b/ConfigGen/configGen.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +from Cheetah.Template import Template +from ConfigDataStructure import configItems, magic, appName + + + +#configItems = [ +# {"label":"_", "key":"magic", "type":"I", "default": ""}, +# {"label":"Config Username", "key":"confUser", "type":"C", "length":16, "default":"admin"}, +# {"label":"Config Password", "key":"confPasswd", "type":"C", "length":16, "default":"geheim123"}, +# {"label":"Wifi SSID", "key":"wifiSsid", "type":"C", "length":32, "default":"test"}, +# {"label":"Wifi Key", "key":"wifiKey", "type":"C", "length":64, "default":"geheim"}, +# {"label":"MQTT Broker", "key":"mqttBroker", "type":"C", "length":32, "default":"broker.hottis.de"}, +# {"label":"MQTT Username", "key":"mqttUser", "type":"C", "length":32, "default":"RgbLed1"}, +# {"label":"MQTT Password", "key":"mqttPass", "type":"C", "length":32, "default":"geheim123"}, +# {"label":"MQTT ClientId", "key":"mqttClientId", "type":"C", "length":32, "default":"RgbLed1"}, +# {"label":"MQTT Port", "key":"mqttPort", "type":"I", "default":8883}, +# {"label":"MQTT Topic Color Command", "key":"mqttTopicColorCommand", "type":"C", "length":64, "default":"IoT/RgbLed1/ColorCommand"}, +# {"label":"MQTT Topic Command", "key":"mqttTopicCommand", "type":"C", "length":64, "default":"IoT/RgbLed1/Command"}, +# {"label":"MQTT DebugTopic", "key":"mqttDebugTopic", "type":"C", "length":64, "default":"IoT/RgbLed1/Debug"}, +# {"label":"DebugMode", "key":"debugMode", "type":"I", "default":0} +#] + + +confWifiSsid = "espconfig" + +params = { + "magic":magic, + "appName":appName, + "confWifiSsid":confWifiSsid, + "configItems":configItems +} + +h_file = Template(file="configuration_h.tmpl", searchList=[params]) +open('configuration.h','w').write(str(h_file)) +c_file = Template(file="configuration_c.tmpl", searchList=[params]) +open('configuration.cpp','w').write(str(c_file)) diff --git a/ConfigGen/configGen.sh b/ConfigGen/configGen.sh new file mode 100755 index 0000000..4d5d960 --- /dev/null +++ b/ConfigGen/configGen.sh @@ -0,0 +1,12 @@ +#!/bin/bash + + +export PROJECTDIR=$PWD/../../.. + +export PYTHONPATH=$PYTHONPATH:$PROJECTDIR/sketch + +python -B configGen.py + +mv configuration.cpp configuration.h $PROJECTDIR/libraries/includes + + diff --git a/ConfigGen/configuration_c.tmpl b/ConfigGen/configuration_c.tmpl new file mode 100644 index 0000000..9bf61a9 --- /dev/null +++ b/ConfigGen/configuration_c.tmpl @@ -0,0 +1,153 @@ +#raw +#include + +#include +#include +#include + +#include "defines.h" +#include "configuration.h" +#end raw + + +tConfigBlock configBlock; +const uint32_t MAGIC = $magic; +const char* CONFIG_SSID = "$confWifiSsid"; +extern ESP8266WebServer webServer; + +bool configSaved = false; + + +static bool checkAuthentication() { + Serial.print("User: "); Serial.println(configBlock.confUser); + Serial.print("Pass: "); Serial.println(configBlock.confPasswd); + return webServer.authenticate(configBlock.confUser, configBlock.confPasswd); +} + +void configServeIndex() { + bool configValid = (configBlock.magic == MAGIC); + + if (! configValid) { + configBlock.magic = MAGIC; + #for $configItem in $configItems + #if $configItem.label != "_" + #if $configItem.type == "C" + strcpy(configBlock.$configItem.key, "$configItem.default"); + #else if $configItem.type == "I" + configBlock.$configItem.key = $configItem.default; + #end if + #end if + #end for + } + + if (! checkAuthentication()) { + return webServer.requestAuthentication(); + } + + + String buffer = + "" + " " + " $appName" + " " + " " + "

$appName - ESP8266 Configuration Page

"; + + if (configSaved) { + configSaved = false; + buffer += "

Configuration saved

"; + } + + buffer += + "
" + " " + #for $configItem in $configItems + #if $configItem.label != "_" + " " + " " + " " + #end if + #end for + " " + " " + " " + "
" + " " + " " + " " + "
" + " " + "
" + "
" + " " + ""; + + webServer.send(200, "text/html", buffer); + + +#ifdef DEBUG + Serial.println("indexHtml request served"); +#endif +} + +void configServeGetConfiguration() { + if (! checkAuthentication()) { + return webServer.requestAuthentication(); + } + + String arg; + + #for $configItem in $configItems + #if $configItem.label != "_" + arg = webServer.arg("$configItem.key"); + #if $configItem.type == "C" + strcpy(configBlock.$configItem.key, arg.c_str()); + #else if $configItem.type == "I" + configBlock.$configItem.key = atoi(arg.c_str()); + #end if + #end if + #end for + + configBlock.magic = MAGIC; + + showConfiguration(); + + EEPROM.begin(512); + EEPROM.put(EEPROM_ADDR, configBlock); + EEPROM.commit(); + + Serial.println("EEPROM saved"); + + configSaved = true; + webServer.sendHeader("Location", String("/"), true); + webServer.send(302, "text/plain", ""); + //webServer.send(200, "text/html", "configuration saved"); +} + +void showConfiguration() { + Serial.println("Configuration is"); + + #for $configItem in $configItems + Serial.print("$configItem.key = <"); + Serial.print(configBlock.$configItem.key); + Serial.println(">"); + + #end for + + Serial.println("---"); +} \ No newline at end of file diff --git a/ConfigGen/configuration_h.tmpl b/ConfigGen/configuration_h.tmpl new file mode 100644 index 0000000..e528f14 --- /dev/null +++ b/ConfigGen/configuration_h.tmpl @@ -0,0 +1,17 @@ +typedef struct { +#for $configItem in $configItems +#if $configItem.type == 'C' + char ${configItem.key}[$configItem.length]; +#else if $configItem.type == 'I' + uint32_t $configItem.key; +#end if +#end for +} tConfigBlock; + +extern const uint32_t MAGIC; +extern tConfigBlock configBlock; +extern const char* CONFIG_SSID; + +void configServeIndex(); +void configServeGetConfiguration(); +void showConfiguration(); \ No newline at end of file diff --git a/sketch/config.cpp b/sketch/config.cpp deleted file mode 100644 index 475f395..0000000 --- a/sketch/config.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include "config.h" -#include "LoRaWan_APP.h" - - -#if 0 -/* OTAA para*/ -uint8_t devEui[] = { 0x22, 0x32, 0x33, 0x00, 0x00, 0x88, 0x88, 0x02 }; -uint8_t appEui[] = { 0xa0, 0x57, 0x81, 0x00, 0x01, 0x12, 0xaa, 0xf3 }; -uint8_t appKey[] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }; - - -/* ABP para*/ -uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda,0x85 }; -uint8_t appSKey[] = { 0xd7, 0x2c, 0x78, 0x75, 0x8c, 0xdc, 0xca, 0xbf, 0x55, 0xee, 0x4a, 0x77, 0x8d, 0x16, 0xef,0x67 }; -uint32_t devAddr = ( uint32_t )0x007e6ae1; - -void configInit() { - -} - -#else - -config_t myConfig = { - .devEui = { 0x22, 0x32, 0x33, 0x00, 0x00, 0x88, 0x88, 0x02 }, - .appEui = { 0xa0, 0x57, 0x81, 0x00, 0x01, 0x12, 0xaa, 0xf3 }, - .appKey = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, - .nwkSKey = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, - .appSKey = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, - .devAddr = 0, - .overTheAirActivation = true, - .modbus_poll_slots = { - { .typ = INPUT_REGISTERS, .id = 7, .address = 0x01 }, - { .typ = INPUT_REGISTERS, .id = 7, .address = 0x02 }, - { .typ = UNASSIGNED, .id = 0, .address = 0 }, - } -}; - -// these variables are defined as externals in the LoRaWAN stack -uint8_t devEui[sizeof(myConfig.devEui)]; -uint8_t appEui[sizeof(myConfig.appEui)]; -uint8_t appKey[sizeof(myConfig.appKey)]; -uint8_t nwkSKey[sizeof(myConfig.nwkSKey)]; -uint8_t appSKey[sizeof(myConfig.appSKey)]; -uint32_t devAddr; -LoRaMacRegion_t loraWanRegion; -bool overTheAirActivation; - -void configInit() { - memcpy(devEui, myConfig.devEui, sizeof(devEui)); - memcpy(appEui, myConfig.appEui, sizeof(appEui)); - memcpy(appKey, myConfig.appKey, sizeof(appKey)); - memcpy(nwkSKey, myConfig.nwkSKey, sizeof(nwkSKey)); - memcpy(appSKey, myConfig.appSKey, sizeof(appSKey)); - devAddr = myConfig.devAddr; - loraWanRegion = LORAMAC_REGION_EU868; - overTheAirActivation = myConfig.overTheAirActivation; -} -#endif - diff --git a/sketch/config.h b/sketch/config.h deleted file mode 100644 index 0d2a350..0000000 --- a/sketch/config.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -#include -#include -#include - - -#define MAX_MODBUS_POLL_SLOTS 16 - -#define UNASSIGNED 0 -#define COILS 1 -#define DISCRETE_INPUTS 2 -#define HOLDING_REGISTERS 3 -#define INPUT_REGISTERS 4 - -typedef struct modbus_poll_s { - int typ; - int id; - int address; -} modbus_poll_t; - -typedef struct config_s { - uint8_t devEui[8]; - uint8_t appEui[8]; - uint8_t appKey[16]; - uint8_t nwkSKey[16]; - uint8_t appSKey[16]; - uint32_t devAddr; - bool overTheAirActivation; - modbus_poll_t modbus_poll_slots[MAX_MODBUS_POLL_SLOTS]; -} config_t; - - -void configInit(); - - - -#endif /* _CONFIG_H_ */ \ No newline at end of file diff --git a/sketch/configuration.cpp b/sketch/configuration.cpp index af4ab8f..f26f2d9 100644 --- a/sketch/configuration.cpp +++ b/sketch/configuration.cpp @@ -1,18 +1,67 @@ #include "configuration.h" #include "defines.h" +#include "LoRaWan_APP.h" #include +#include +#include +#include #include #include "HT_SSD1306Wire.h" #include #include +#include #include +#include +#include +#include + + + + +const uint32_t MAGIC = 0xaffe0001; + + +config_t myConfig = { + .magic = MAGIC, + .appEui = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .appKey = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .modbus_poll_slots = { + { .typ = INPUT_REGISTERS, .id = 7, .address = 0x01 }, + { .typ = INPUT_REGISTERS, .id = 7, .address = 0x02 }, + { .typ = UNASSIGNED, .id = 0, .address = 0 }, + } +}; + +uint8_t devEui[8]; +uint8_t appEui[8]; +uint8_t appKey[16]; +uint8_t nwkSKey[16]; +uint8_t appSKey[16]; +uint32_t devAddr; +LoRaMacRegion_t loraWanRegion; +bool overTheAirActivation; + + SSD1306Wire confDisplay(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED);; // addr , freq , i2c group , resolution , rst +WebServer server(80); const char *ssid = "ModbusLoraConf"; + +#define TEST_PASSWORD +#ifndef TEST_PASSWORD char password[12]; +#else +const char *password = "test1234"; +#endif + +extern uint8_t devEui[8]; + +bool configSaved = false; +int configParsingFailed = 0; +enum { PARSING_OK, PARSING_INVALID, PARSING_TOO_MANY, PARSING_TOO_FEW } configParsingError; static void displayStatus(uint8_t numOfStations) { confDisplay.clear(); @@ -43,17 +92,142 @@ static void displayInit() { confDisplay.display(); } + +static void handleRoot() { + // bool configValid = (configBlock.magic == MAGIC); + std::stringstream buffer; + buffer << "" + " " + " Modbus LoRaWAN Gateway" + " " + " " + "

Modbus LoRaWAN Gateway - Configuration Page

"; + if (configSaved) { + configSaved = false; + buffer << "

Configuration saved

"; + } + if (configParsingFailed) { + configParsingFailed = 0; + buffer << "

Error when parsing field " << configParsingFailed << ", error " << configParsingError << "

"; + } + buffer << "
" + " " + " " + " " + " " + " " + " " + " " + " " + " " + "
" + " DevEui" + " "; + buffer << " (readonly)"; + buffer << "
" + " AppEui" + " "; + buffer << " "; + buffer << "
" + " AppKey" + " "; + buffer << " "; + buffer << "
" + " " + "
" + "
" + " = reqTokens) { + Serial.println("too many tokens"); + configParsingFailed = fieldNum; + configParsingError = PARSING_TOO_MANY; + break; + } + dest[i] = v; + i++; + } + if ((i != reqTokens) && (configParsingFailed == 0)) { + Serial.println("too few tokens"); + configParsingFailed = fieldNum; + configParsingError = PARSING_TOO_FEW; + } + +} + +static void handleConfigSave() { + char *arg1 = (char*)server.arg("AppEui").c_str(); + Serial.printf("AppEui: %s\n\r", arg1); + parseField(arg1, 1, 8, myConfig.appEui); + + if (!configParsingFailed) { + char *arg2 = (char*)server.arg("AppKey").c_str(); + Serial.printf("AppKey: %s\n\r", arg2); + parseField(arg2, 2, 16, myConfig.appKey); + } + + configSaved = !configParsingFailed; + server.sendHeader("Location", String("/"), true); + server.send(302, "text/plain", ""); +} + + void configurationSetup() { +#ifndef TEST_PASSWORD memset(password, 0, sizeof(password)); for (int i = 0; i < sizeof(password) - 1; i++) { password[i] = random(65, 90); } +#endif WiFi.softAP(ssid, password); IPAddress myIP = WiFi.softAPIP(); displayInit(); displayStatus(0); + + LoRaWAN.generateDeveuiByChipID(); + server.on("/", handleRoot); + server.on("/config", handleConfigSave); + server.begin(); } @@ -65,4 +239,14 @@ void configurationLoop() { numOfStations = currentNumOfStations; } + server.handleClient(); +} + + + +void configLoad() { + memcpy(appEui, myConfig.appEui, sizeof(appEui)); + memcpy(appKey, myConfig.appKey, sizeof(appKey)); + loraWanRegion = LORAMAC_REGION_EU868; + overTheAirActivation = true; } \ No newline at end of file diff --git a/sketch/configuration.h b/sketch/configuration.h index 8eb3159..73ecc70 100644 --- a/sketch/configuration.h +++ b/sketch/configuration.h @@ -2,8 +2,39 @@ #define _CONFIGURATION_H_ + +#include +#include +#include + + +#define MAX_MODBUS_POLL_SLOTS 16 + +#define UNASSIGNED 0 +#define COILS 1 +#define DISCRETE_INPUTS 2 +#define HOLDING_REGISTERS 3 +#define INPUT_REGISTERS 4 + +typedef struct modbus_poll_s { + int typ; + int id; + int address; +} modbus_poll_t; + +typedef struct config_s { + uint32_t magic; + uint8_t appEui[8]; + uint8_t appKey[16]; + modbus_poll_t modbus_poll_slots[MAX_MODBUS_POLL_SLOTS]; +} config_t; + + + void configurationSetup(); void configurationLoop(); +void configLoad(); + #endif // _CONFIGURATION_H_ diff --git a/sketch/production.cpp b/sketch/production.cpp index bca3910..c36e76b 100644 --- a/sketch/production.cpp +++ b/sketch/production.cpp @@ -2,7 +2,7 @@ #include #include #include "defines.h" -#include "config.h" +#include "configuration.h" #include @@ -121,9 +121,7 @@ void productionLoop() case DEVICE_STATE_INIT: digitalWrite(LED_GREEN, LOW); { -#if(LORAWAN_DEVEUI_AUTO) LoRaWAN.generateDeveuiByChipID(); -#endif LoRaWAN.init(loraWanClass,loraWanRegion); break; } diff --git a/sketch/sketch.ino b/sketch/sketch.ino index 204add3..e499a20 100644 --- a/sketch/sketch.ino +++ b/sketch/sketch.ino @@ -20,7 +20,7 @@ void setup() { Serial.begin(115200); - configInit(); + configLoad(); if (productionMode) { productionSetup(); diff --git a/startDevEnv.sh b/startDevEnv.sh index a62c92f..4a26453 100755 --- a/startDevEnv.sh +++ b/startDevEnv.sh @@ -4,6 +4,6 @@ docker run \ -it \ --rm \ -v $PWD:/home/arduino/project \ - registry.hottis.de/dockerized/build-env-arduino:0.29.0-9 \ + registry.hottis.de/dockerized/build-env-arduino:0.29.0-10 \ bash