Merge branch 'persitense-refactoring' into develop

This commit is contained in:
2021-10-06 01:08:30 +03:00
committed by GitHub
9 changed files with 489 additions and 308 deletions

View File

@@ -9,8 +9,9 @@
-DSYSLOG_ENABLE -DSYSLOG_ENABLE
# - udp errors # - udp errors
-DOTA -DOTA
#-DARDUINO_OTA_MDNS_DISABLE -DARDUINO_OTA_MDNS_DISABLE
#-DMDNS_ENABLE - ArduinoMDNS didnt working #-DMDNS_ENABLE
#- ArduinoMDNS didnt working
-DMCP23017 -DMCP23017
-DMODBUS_TX_PIN=13 -DMODBUS_TX_PIN=13
@@ -43,3 +44,5 @@
-DFS_STORAGE -DFS_STORAGE
-DFS_PREPARE -DFS_PREPARE
-D CORS=\"http://lazyhome.ru\"

View File

@@ -1,14 +1,24 @@
#include "config.h" #include "config.h"
int systemConfig::openStream(char mode)
{
#if defined(FS_STORAGE)
stream->open("/config.bin",mode);
#else
stream->open(FN_CONFIG_BIN,mode);
#endif
stream->setSize(SYSCONF_SIZE);
};
bool systemConfig::isValidSysConf() bool systemConfig::isValidSysConf()
{ {
if (!stream) return false; if (!stream) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,signature)); stream->seek(offsetof(systemConfigData,signature));
for (int i=0;i<sizeof(systemConfigData::signature);i++) for (int i=0;i<sizeof(systemConfigData::signature);i++)
if (stream->read()!=EEPROM_signature[i]) if (stream->read()!=EEPROM_signature[i])
{ {
stream->close();
return false; return false;
} }
return true; return true;
@@ -18,7 +28,7 @@ bool systemConfig::isValidSysConf()
bool systemConfig::getMAC() bool systemConfig::getMAC()
{ {
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,mac)); stream->seek(offsetof(systemConfigData,mac));
bool isMacValid = false; bool isMacValid = false;
@@ -26,26 +36,32 @@ bool systemConfig::isValidSysConf()
mac[i] = stream->read(); mac[i] = stream->read();
if (mac[i] != 0 && mac[i] != 0xff) isMacValid = true; if (mac[i] != 0 && mac[i] != 0xff) isMacValid = true;
} }
stream->close();
return isMacValid; return isMacValid;
} }
bool systemConfig::setMAC(macAddress& _mac) bool systemConfig::setMAC(macAddress& _mac)
{ {
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('w'); openStream('a');
stream->seek(offsetof(systemConfigData,mac)); stream->seek(offsetof(systemConfigData,mac));
stream->write ((const uint8_t *)&_mac,sizeof(_mac)); stream->write ((const uint8_t *)&_mac,sizeof(_mac));
memcpy(mac, _mac, sizeof(mac)); memcpy(mac, _mac, sizeof(mac));
stream->flush(); stream->close();
return true; return true;
} }
char * systemConfig::getMQTTpwd(char * buffer, uint16_t bufLen) char * systemConfig::getMQTTpwd(char * buffer, uint16_t bufLen)
{ {
if (!stream || !isValidSysConf()) return NULL; if (!stream || !isValidSysConf()) return NULL;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,MQTTpwd)); stream->seek(offsetof(systemConfigData,MQTTpwd));
short bytes=stream->readBytesUntil(0,buffer,bufLen-1); short bytes=stream->readBytesUntil(0,buffer,bufLen-1);
stream->close();
Serial.println("valid");
Serial.println(offsetof(systemConfigData,MQTTpwd));
Serial.println(bytes);
Serial.write(buffer,bytes);
if (bytes) if (bytes)
{ {
buffer[bytes]=0; buffer[bytes]=0;
@@ -57,11 +73,11 @@ bool systemConfig::isValidSysConf()
bool systemConfig::setMQTTpwd(char * pwd) bool systemConfig::setMQTTpwd(char * pwd)
{ {
if (!stream || !isValidSysConf() || (strlen(pwd)>=sizeof(systemConfigData::MQTTpwd))) return false; if (!stream || !isValidSysConf() || (strlen(pwd)>=sizeof(systemConfigData::MQTTpwd))) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,MQTTpwd)); stream->seek(offsetof(systemConfigData,MQTTpwd));
stream->print(pwd); stream->print(pwd);
int bytes = stream->write((uint8_t)'\0'); int bytes = stream->write((uint8_t)'\0');
stream->flush(); stream->close();
return bytes; return bytes;
} }
@@ -69,9 +85,10 @@ bool systemConfig::isValidSysConf()
char * systemConfig::getOTApwd(char * buffer, uint16_t bufLen) char * systemConfig::getOTApwd(char * buffer, uint16_t bufLen)
{ {
if (!stream || !isValidSysConf()) return NULL; if (!stream || !isValidSysConf()) return NULL;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,OTApwd)); stream->seek(offsetof(systemConfigData,OTApwd));
short bytes=stream->readBytesUntil(0,buffer,bufLen-1); short bytes=stream->readBytesUntil(0,buffer,bufLen-1);
stream->close();
if (bytes) if (bytes)
{ {
buffer[bytes]=0; buffer[bytes]=0;
@@ -83,11 +100,11 @@ bool systemConfig::isValidSysConf()
bool systemConfig::setOTApwd(char * pwd) bool systemConfig::setOTApwd(char * pwd)
{ {
if (!stream || !isValidSysConf() || (strlen(pwd)>=sizeof(systemConfigData::OTApwd))) return false; if (!stream || !isValidSysConf() || (strlen(pwd)>=sizeof(systemConfigData::OTApwd))) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,OTApwd)); stream->seek(offsetof(systemConfigData,OTApwd));
stream->print(pwd); stream->print(pwd);
int bytes = stream->write((uint8_t)'\0'); int bytes = stream->write((uint8_t)'\0');
stream->flush(); stream->close();
return bytes; return bytes;
} }
@@ -95,9 +112,10 @@ bool systemConfig::isValidSysConf()
char * systemConfig::getServer(char * buffer, uint16_t bufLen) char * systemConfig::getServer(char * buffer, uint16_t bufLen)
{ {
if (!stream || !isValidSysConf()) return NULL; if (!stream || !isValidSysConf()) return NULL;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,configURL)); stream->seek(offsetof(systemConfigData,configURL));
short bytes=stream->readBytesUntil(0,buffer,bufLen-1); short bytes=stream->readBytesUntil(0,buffer,bufLen-1);
stream->close();
if (bytes) if (bytes)
{ {
buffer[bytes]=0; buffer[bytes]=0;
@@ -109,11 +127,11 @@ bool systemConfig::isValidSysConf()
bool systemConfig::setServer(char* url) bool systemConfig::setServer(char* url)
{ {
if (!stream || !isValidSysConf() || (strlen(url)>=sizeof(systemConfigData::configURL))) return false; if (!stream || !isValidSysConf() || (strlen(url)>=sizeof(systemConfigData::configURL))) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,configURL)); stream->seek(offsetof(systemConfigData,configURL));
stream->print(url); stream->print(url);
int bytes = stream->write((uint8_t)'\0'); int bytes = stream->write((uint8_t)'\0');
stream->flush(); stream->close();
return bytes; return bytes;
} }
@@ -122,10 +140,11 @@ bool systemConfig::isValidSysConf()
{ {
uint32_t addr; uint32_t addr;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,ip)); stream->seek(offsetof(systemConfigData,ip));
stream->readBytes((uint8_t *) &addr,4); stream->readBytes((uint8_t *) &addr,4);
ip=addr; ip=addr;
stream->close();
return (ip[0] && ((ip[0] != 0xff) || (ip[1] != 0xff) || (ip[2] != 0xff) || (ip[3] != 0xff))); return (ip[0] && ((ip[0] != 0xff) || (ip[1] != 0xff) || (ip[2] != 0xff) || (ip[3] != 0xff)));
} }
@@ -133,30 +152,33 @@ bool systemConfig::isValidSysConf()
{ {
uint32_t addr; uint32_t addr;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,mask)); stream->seek(offsetof(systemConfigData,mask));
stream->readBytes((uint8_t *) &addr,4); stream->readBytes((uint8_t *) &addr,4);
mask=addr; mask=addr;
stream->close();
return (mask[0] && ((mask[0] != 0xff) || (mask[1] != 0xff) || (mask[2] != 0xff) || (mask[3] != 0xff))); return (mask[0] && ((mask[0] != 0xff) || (mask[1] != 0xff) || (mask[2] != 0xff) || (mask[3] != 0xff)));
} }
bool systemConfig::getDNS(IPAddress& dns) bool systemConfig::getDNS(IPAddress& dns)
{ uint32_t addr; { uint32_t addr;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,dns)); stream->seek(offsetof(systemConfigData,dns));
stream->readBytes((uint8_t *) &addr,4); stream->readBytes((uint8_t *) &addr,4);
dns = addr; dns = addr;
stream->close();
return (dns[0] && ((dns[0] != 0xff) || (dns[1] != 0xff) || (dns[2] != 0xff) || (dns[3] != 0xff))); return (dns[0] && ((dns[0] != 0xff) || (dns[1] != 0xff) || (dns[2] != 0xff) || (dns[3] != 0xff)));
} }
bool systemConfig::getGW(IPAddress& gw) bool systemConfig::getGW(IPAddress& gw)
{ uint32_t addr; { uint32_t addr;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,gw)); stream->seek(offsetof(systemConfigData,gw));
stream->readBytes((uint8_t *) &addr,4); stream->readBytes((uint8_t *) &addr,4);
gw=addr; gw=addr;
stream->close();
return (gw[0] && ((gw[0] != 0xff) || (gw[1] != 0xff) || (gw[2] != 0xff) || (gw[3] != 0xff))); return (gw[0] && ((gw[0] != 0xff) || (gw[1] != 0xff) || (gw[2] != 0xff) || (gw[3] != 0xff)));
} }
@@ -164,30 +186,30 @@ bool systemConfig::isValidSysConf()
bool systemConfig::setIP(IPAddress& ip) bool systemConfig::setIP(IPAddress& ip)
{ uint32_t addr=ip; { uint32_t addr=ip;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('r'); openStream('r');
stream->seek(offsetof(systemConfigData,ip)); stream->seek(offsetof(systemConfigData,ip));
int bytes = stream->write((uint8_t *) &addr, 4); int bytes = stream->write((uint8_t *) &addr, 4);
stream->flush(); stream->close();
return bytes; return bytes;
} }
bool systemConfig::setMask(IPAddress& mask) bool systemConfig::setMask(IPAddress& mask)
{ uint32_t addr = mask; { uint32_t addr = mask;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,mask)); stream->seek(offsetof(systemConfigData,mask));
int bytes = stream->write((uint8_t *) &addr, 4); int bytes = stream->write((uint8_t *) &addr, 4);
stream->flush(); stream->close();
return bytes; return bytes;
} }
bool systemConfig::setDNS(IPAddress& dns) bool systemConfig::setDNS(IPAddress& dns)
{ uint32_t addr = dns; { uint32_t addr = dns;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,dns)); stream->seek(offsetof(systemConfigData,dns));
int bytes = stream->write((uint8_t *) &addr, 4); int bytes = stream->write((uint8_t *) &addr, 4);
stream->flush(); stream->close();
return bytes; return bytes;
} }
@@ -195,10 +217,10 @@ bool systemConfig::isValidSysConf()
bool systemConfig::setGW(IPAddress& gw) bool systemConfig::setGW(IPAddress& gw)
{ uint32_t addr = gw; { uint32_t addr = gw;
if (!stream || !isValidSysConf()) return false; if (!stream || !isValidSysConf()) return false;
stream->open('w'); openStream('r');
stream->seek(offsetof(systemConfigData,gw)); stream->seek(offsetof(systemConfigData,gw));
int bytes = stream->write((uint8_t *) &addr, 4); int bytes = stream->write((uint8_t *) &addr, 4);
stream->flush(); stream->close();
return bytes; return bytes;
} }
@@ -206,7 +228,7 @@ bool systemConfig::isValidSysConf()
bool systemConfig::clear() bool systemConfig::clear()
{ {
if (!stream) return false; if (!stream) return false;
stream->open('w'); openStream('w');
stream->seek(0); stream->seek(0);
for (unsigned int i = 0; i < stream->getSize(); i++) { for (unsigned int i = 0; i < stream->getSize(); i++) {
stream->write((uint8_t)'\0'); stream->write((uint8_t)'\0');
@@ -214,7 +236,7 @@ bool systemConfig::isValidSysConf()
stream->seek(offsetof(systemConfigData,signature)); stream->seek(offsetof(systemConfigData,signature));
for (unsigned int i=0;i<sizeof(systemConfigData::signature);i++) for (unsigned int i=0;i<sizeof(systemConfigData::signature);i++)
if (stream->write(EEPROM_signature[i])); if (stream->write(EEPROM_signature[i]));
stream->flush(); stream->close();
return true; return true;
} }

View File

@@ -6,57 +6,14 @@
#include <Arduino.h> #include <Arduino.h>
#include "flashstream.h" #include "flashstream.h"
#include <IPAddress.h> #include <IPAddress.h>
#include "systemconfigdata.h"
#define MAXFLASHSTR 32
#define PWDFLASHSTR 16
#define EEPROM_SIGNATURE "LHCF"
#define EEPROM_SIGNATURE_LENGTH 4
const char EEPROM_signature[] = EEPROM_SIGNATURE;
#define SYSCONF_OFFSET 0
#define EEPROM_offset_NotAlligned SYSCONF_OFFSET+sizeof(systemConfigData)
#define EEPROM_offsetJSON EEPROM_offset_NotAlligned + (4 -(EEPROM_offset_NotAlligned & 3))
//#define EEPROM_offsetJSON IFLASH_PAGE_SIZE
#define EEPROM_FIX_PART_LEN EEPROM_offsetJSON-SYSCONF_OFFSET
typedef char flashstr[MAXFLASHSTR];
typedef char flashpwd[PWDFLASHSTR];
typedef uint8_t macAddress[6];
#pragma pack(push, 1)
typedef struct
{
char signature[4];
macAddress mac; //6 bytes
union {
uint16_t configFlags;
struct
{
uint8_t serialDebugLevel:4;
uint8_t syslogDebugLevel:4;
uint8_t notGetConfigFromHTTP:1;
uint8_t saveToFlash:1;
};
};
uint32_t ip;
uint32_t dns;
uint32_t gw;
uint32_t mask;
flashstr configURL;
flashpwd MQTTpwd;
flashpwd OTApwd;
uint16_t sysConfigHash;
uint16_t JSONHash;
} systemConfigData;
#pragma (pop)
class systemConfig { class systemConfig {
private: private:
flashStream * stream; flashStream * stream;
int openStream(char mode = '\0');
public: public:
macAddress mac; macAddress mac;
systemConfig() {stream=NULL;}; systemConfig() {stream=NULL;};

View File

@@ -1,4 +1,39 @@
#include <flashstream.h> #include "flashstream.h"
#include "systemconfigdata.h"
#include <main.h>
#include <WiFiOTA.h>
#if defined(ARDUINO_ARCH_AVR)
#include <EEPROM.h>
#endif
#if defined(ESP32) && !defined(FS_STORAGE)
#include <EEPROM.h>
#endif
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP_EEPROM.h>
#endif
#if defined(__SAM3X8E__)
#include <DueFlashStorage.h>
extern DueFlashStorage EEPROM;
#endif
#ifdef NRF5
#include <NRFFlashStorage.h> //STUB
extern NRFFlashStorage EEPROM;
#endif
#ifdef ARDUINO_ARCH_STM32
#include <NRFFlashStorage.h> //STUB
extern NRFFlashStorage EEPROM;
#endif
#if defined(__SAM3X8E__) #if defined(__SAM3X8E__)
DueFlashStorage EEPROM; DueFlashStorage EEPROM;
@@ -11,3 +46,184 @@ NRFFlashStorage EEPROM;
#ifdef ARDUINO_ARCH_STM32 #ifdef ARDUINO_ARCH_STM32
NRFFlashStorage EEPROM; NRFFlashStorage EEPROM;
#endif #endif
#if defined(FS_STORAGE)
int flashStream::open(String _filename, char mode)
{
char modestr[4];
modestr[0]=mode; modestr[1]='b'; modestr[2]='+'; modestr[3]='\0';
if (fs) fs.close();
filename=_filename;
if (fs = SPIFFS.open(_filename,modestr))
{
openedMode=mode;
if (_filename.endsWith(".json")) {contentType=HTTP_TEXT_JSON;textMode=true;}
else if (_filename.endsWith(".bin")) {contentType=HTTP_OCTET_STREAM;textMode=false;}
else if (_filename.endsWith(".txt")) {contentType=HTTP_TEXT_PLAIN;textMode=true;}
else if (_filename.endsWith(".html")) {contentType=HTTP_TEXT_HTML;textMode=true;}
else if (_filename.endsWith(".gif")) {contentType=HTTP_IMAGE_GIF;textMode=false;}
else if (_filename.endsWith(".jpg")) {contentType=HTTP_IMAGE_JPEG;textMode=false;}
debugSerial<<(F("Opened ("))<<modestr<<(F(")"))<<filename<<endl;
return fs;
}
else
{
openedMode='\0';
debugSerial<<("Open error (")<<modestr<<(")")<<filename<<endl;
return 0;
}
};
int flashStream::available()
{
if (!fs) return 0;
if (textMode && peek()==EOFchar) return 0;
return fs.available();
};
int flashStream::read() {
return fs.read();
};
int flashStream::peek() {
return fs.peek();
};
unsigned int flashStream::seek (unsigned int _pos)
{
debugSerial<<(F("Seek:"))<<_pos;
if (_pos>streamSize) _pos=streamSize;
unsigned int res = fs.seek(_pos,SeekSet);
debugSerial<<(F(" Res:"))<<res<<endl;
return res;
};
void flashStream::close() {fs.close(); };
void flashStream::flush() {fs.flush(); };
size_t flashStream::write(uint8_t ch)
{
return fs.write(ch);
};
flashStream::~flashStream () {if (fs) fs.close();} ;
#else
void flashStream::setSize(unsigned int _size) {streamSize=_size;};
int flashStream::open(short fileNum, char mode)
{
switch (fileNum) {
case FN_CONFIG_JSON:
pos = 0;
//streamSize = _size;
startPos = EEPROM_offsetJSON;
textMode = true;
contentType = HTTP_TEXT_JSON;
return 1;
case FN_CONFIG_BIN:
pos = 0;
startPos = SYSCONF_OFFSET;
streamSize = SYSCONF_SIZE;
textMode =false;
contentType = HTTP_OCTET_STREAM;
return 1;
default:
return 0;
}
};
int flashStream::open(String _filename, char mode)
{
if (_filename == "/config.json") return open (FN_CONFIG_JSON,mode);
else if (_filename == "/config.bin") return open (FN_CONFIG_BIN,mode);
else return 0;
};
/*
virtual int open(unsigned int _startPos=0, unsigned int _size=4096 char mode='\0')
{
pos = 0;
startPos = _startPos;
streamSize = _size;
return 1;
};
*/
unsigned int flashStream::seek(unsigned int _pos)
{ pos=min(_pos, streamSize);
debugSerial<<F("Seek:")<<pos<<endl;
return pos;
};
int flashStream::available() {
//debugSerial<<pos<<"%"<<streamSize<<";";
if (textMode && peek()==EOFchar) return 0;
return (pos<streamSize);
};
int flashStream::read()
{
int ch = peek();
pos++;
//debugSerial<<"<"<<(char)ch;
return ch;
};
int flashStream::peek()
{
if (pos<streamSize)
return EEPROM.read(pos);
else return -1;
};
void flashStream::flush() {
#if defined(ESP8266) || defined(ESP32)
if (EEPROM.commitReset())
infoSerial<<"Commited to FLASH"<<endl;
else errorSerial<<"Commit error. len:"<<EEPROM.length()<<endl;
#endif
};
size_t flashStream::write(uint8_t ch)
{
//debugSerial<<">"<<(char)ch;
#if defined(__AVR__)
EEPROM.update(startPos+pos++,(char)ch);
return 1;
#elif defined(__SAM3X8E__)
return EEPROM.write(startPos+pos++,(char)ch);
#else
EEPROM.write(startPos+pos++,(char)ch);
return 1;
#endif
};
#if defined(__SAM3X8E__)
size_t flashStream::write(const uint8_t *buffer, size_t size)
{
//debugSerial<<("Write from:")<<pos<<" "<<size<<" bytes"<<endl;
EEPROM.write(startPos+pos,(byte*)buffer,size);
pos+=size;
return size;
};
#endif
#if defined(ESP8266) || defined(ESP32)
void flashStream::putEOF()
{
write (255);
EEPROM.commit();
};
#endif
void flashStream::close()
{
flush();
}
#endif

View File

@@ -1,199 +1,89 @@
#pragma once #pragma once
#ifndef _FLASHSTREAM_H_ //#ifndef _FLASHSTREAM_H_
#define _FLASHSTREAM_H_ //#define _FLASHSTREAM_H_
#include <main.h>
#include <Stream.h>
#include <Arduino.h>
#include "seekablestream.h"
//#include "config.h"
#if defined(FS_STORAGE) #if defined(FS_STORAGE)
#include <FS.h> #include <FS.h>
#include <SPIFFS.h> #include <SPIFFS.h>
#endif #endif
#if defined(ARDUINO_ARCH_AVR) #define FN_CONFIG_JSON 1
#include <EEPROM.h> #define FN_CONFIG_BIN 2
#endif
#if defined(ESP32) && !defined(FS_STORAGE)
#include <EEPROM.h>
#endif
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP_EEPROM.h>
#endif
#if defined(__SAM3X8E__)
#include <DueFlashStorage.h>
extern DueFlashStorage EEPROM;
#endif
#ifdef NRF5
#include <NRFFlashStorage.h> //STUB
extern NRFFlashStorage EEPROM;
#endif
#ifdef ARDUINO_ARCH_STM32
#include <NRFFlashStorage.h> //STUB
extern NRFFlashStorage EEPROM;
#endif
#include <Stream.h>
#include <Arduino.h>
class seekableStream : public Stream
{
protected:
unsigned int streamSize;
public:
seekableStream(unsigned int size):Stream(),streamSize(size) {};
unsigned int getSize() {return streamSize;}
virtual unsigned int seek(unsigned int _pos = 0) = 0;
};
#if defined(FS_STORAGE) #if defined(FS_STORAGE)
class flashStream : public seekableStream class flashStream : public seekableStream
{ {
private: private:
File fs; String filename;
String filename; char openedMode;
char openedMode; File fs;
public: public:
flashStream(String _filename):seekableStream(65535) flashStream():seekableStream(65535)
{ {
filename=_filename;
openedMode='\0'; openedMode='\0';
open('r'); filename = "";
} };
virtual int open(String _filename, char mode) override;
int open(char mode='\0') virtual int available() override;
{ virtual int read();
if (!mode && openedMode) mode=openedMode; virtual int peek();
if (!mode && !openedMode) mode='r'; virtual unsigned int seek (unsigned int _pos = 0) override;
if (openedMode!=mode) virtual void close() override;
{ virtual void flush() override;
char modestr[2]; virtual size_t write(uint8_t ch);
modestr[0]=mode;modestr[1]=0;
unsigned int savedPos=fs.position();
if (fs) fs.close();
if (fs = SPIFFS.open(filename,modestr))
{
openedMode=mode;
fs.seek(savedPos);
debugSerial<<("Opened/")<<modestr<<(":")<<filename<<endl;
}
else
{
openedMode='\0';
debugSerial<<("Open error/")<<modestr<<(":")<<filename<<endl;
}
}
return fs;
}
virtual int available() { if (!fs) return 0; return fs.available(); };
virtual int read() {open('r');return fs.read();};
virtual int peek() {open('r'); return fs.peek();};
virtual unsigned int seek(unsigned int _pos = 0){return open();fs.seek(_pos,SeekSet);};
virtual void flush() {fs.flush(); open('r'); };
virtual size_t write(uint8_t ch) {open('w'); return fs.write(ch);};
using Print::write; using Print::write;
void putEOF(){write (255);}; virtual ~flashStream ();
virtual ~flashStream () {if (fs) fs.close();} ;
}; };
#else #else
#define MAX_STREAM_SIZE 4096
class flashStream : public seekableStream class flashStream : public seekableStream
{ {
protected: protected:
unsigned int pos; unsigned int pos;
unsigned int startPos; unsigned int startPos;
public: public:
flashStream(unsigned int _startPos=0, unsigned int _size=4096 ):seekableStream(_size) flashStream():seekableStream(MAX_STREAM_SIZE){};
void setSize(unsigned int _size);
int open(short fileNum, char mode='\0') ;
virtual int open(String _filename, char mode='\0') override;
/*
virtual int open(unsigned int _startPos=0, unsigned int _size=4096 char mode='\0')
{ {
pos = _startPos; startPos = _startPos; pos = 0;
startPos = _startPos;
streamSize = _size;
return 1;
}; };
*/
virtual unsigned int seek(unsigned int _pos = 0);
virtual int available() override;
virtual int read() ;
virtual int peek() ;
virtual void flush();
virtual size_t write(uint8_t ch) ;
void setSize(unsigned int _size) {streamSize=_size;}; #if defined(__SAM3X8E__)
int open(bool write=false) {return 1;}; virtual size_t write(const uint8_t *buffer, size_t size) override;
#else
virtual unsigned int seek(unsigned int _pos = 0) using Print::write;//(const uint8_t *buffer, size_t size);
{ pos=min(startPos+_pos, startPos+streamSize);
debugSerial<<F("Seek:")<<pos<<endl;
return pos;
};
virtual int available() {
//debugSerial<<pos<<"%"<<streamSize<<";";
return (pos<streamSize);
};
virtual int read()
{
int ch = peek();
pos++;
//debugSerial<<"<"<<(char)ch;
return ch;
};
virtual int peek()
{
if (pos<streamSize)
return EEPROM.read(pos);
else return -1;
};
virtual void flush() {
#if defined(ESP8266) || defined(ESP32)
if (EEPROM.commitReset())
infoSerial<<"Commited to FLASH"<<endl;
else errorSerial<<"Commit error. len:"<<EEPROM.length()<<endl;
#endif
};
virtual size_t write(uint8_t ch)
{
//debugSerial<<">"<<(char)ch;
#if defined(__AVR__)
EEPROM.update(pos++,(char)ch);
return 1;
#elif defined(__SAM3X8E__)
return EEPROM.write(pos++,(char)ch);
#else
EEPROM.write(pos++,(char)ch);
return 1;
#endif
// #if defined(__SAM3X8E__)
// return EEPROM.write(pos++,(char)ch);
// #else
// EEPROM.update(pos++,(char)ch);
// return 1;
// #endif
// return 0;
};
#if defined(__SAM3X8E__)
virtual size_t write(const uint8_t *buffer, size_t size) override
{
//debugSerial<<("Write from:")<<pos<<" "<<size<<" bytes"<<endl;
EEPROM.write(pos,(byte*)buffer,size);
pos+=size;
return size;
};
#else
using Print::write;//(const uint8_t *buffer, size_t size);
#endif
void putEOF(){write (255);
#if defined(ESP8266) || defined(ESP32)
EEPROM.commit();
#endif #endif
};
#if defined(ESP8266) || defined(ESP32)
virtual void putEOF() override ;
#endif
virtual void close() override;
}; };
#endif #endif
#endif //#endif

View File

@@ -418,7 +418,7 @@ void Item::setExt(long int par) // Only store if VAL is int (autogenerated or c
{ {
if (!itemExt) if (!itemExt)
{ {
for (int i = aJson.getArraySize(itemArr); i <= 4; i++) for (int i = aJson.getArraySize(itemArr); i <= I_EXT; i++)
aJson.addItemToArray(itemArr, itemExt=aJson.createNull());// Item((long int)0)); aJson.addItemToArray(itemArr, itemExt=aJson.createNull());// Item((long int)0));
//itemExt = aJson.getArrayItem(itemArr, I_EXT); //itemExt = aJson.getArrayItem(itemArr, I_EXT);
}; };
@@ -696,8 +696,8 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
/// DELAYED COMMANDS processing /// DELAYED COMMANDS processing
if (suffixCode == S_DELAYED) if (suffixCode == S_DELAYED)
{ {
for (int i = aJson.getArraySize(itemArr); i < I_TIMESTAMP+1; i++) for (int i = aJson.getArraySize(itemArr); i <= I_TIMESTAMP; i++)
aJson.addItemToArray(itemArr, aJson.createItem( (long int) 0)); aJson.addItemToArray(itemArr, aJson.createNull());
aJsonObject *timestampObj = aJson.getArrayItem(itemArr, I_TIMESTAMP); aJsonObject *timestampObj = aJson.getArrayItem(itemArr, I_TIMESTAMP);
if (timestampObj && cmd.getCmd()<=0xf) if (timestampObj && cmd.getCmd()<=0xf)
@@ -705,6 +705,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
if (cmd.getInt()>0) if (cmd.getInt()>0)
{ {
timestampObj->valueint = millis()+cmd.getInt(); timestampObj->valueint = millis()+cmd.getInt();
timestampObj->type = aJson_Int;
timestampObj->subtype=cmd.getCmd(); timestampObj->subtype=cmd.getCmd();
debugSerial<<F( "Armed for ")<< cmd.getInt() << F(" ms :")<<timestampObj->valueint<<endl; debugSerial<<F( "Armed for ")<< cmd.getInt() << F(" ms :")<<timestampObj->valueint<<endl;
} }

View File

@@ -48,6 +48,7 @@ Streamlog errorSerial(&debugSerialPort,LOG_ERROR, ledRED);
Streamlog infoSerial (&debugSerialPort,LOG_INFO); Streamlog infoSerial (&debugSerialPort,LOG_INFO);
#endif #endif
/*
#if defined(FS_STORAGE) #if defined(FS_STORAGE)
flashStream sysConfStream("/config.bin"); flashStream sysConfStream("/config.bin");
flashStream JSONStream("/config.json"); flashStream JSONStream("/config.json");
@@ -55,6 +56,9 @@ flashStream JSONStream("/config.json");
flashStream sysConfStream(SYSCONF_OFFSET,EEPROM_offsetJSON); flashStream sysConfStream(SYSCONF_OFFSET,EEPROM_offsetJSON);
flashStream JSONStream(EEPROM_offsetJSON,MAX_JSON_CONF_SIZE); flashStream JSONStream(EEPROM_offsetJSON,MAX_JSON_CONF_SIZE);
#endif #endif
*/
flashStream sysConfStream;
systemConfig sysConf(&sysConfStream); systemConfig sysConf(&sysConfStream);
@@ -172,20 +176,23 @@ if (configLocked)
errorSerial<<F("Not unlocked in 10s - continue ...")<<endl; errorSerial<<F("Not unlocked in 10s - continue ...")<<endl;
} }
debugSerial<<F("Stopping channels ...")<<endl; if (root && items)
//Stoping the channels {
aJsonObject * item = items->child; debugSerial<<F("Stopping channels ...")<<endl;
while (items && item) //Stoping the channels
{ aJsonObject * item = items->child;
if (item->type == aJson_Array && aJson.getArraySize(item)>0) while (item)
{ {
Item it(item->name); if (item->type == aJson_Array && aJson.getArraySize(item)>0)
if (it.isValid()) it.Stop(); {
yield(); Item it(item->name);
if (it.isValid()) it.Stop();
yield();
}
item = item->next;
} }
item = item->next; }
}
pollingItem = NULL; pollingItem = NULL;
debugSerial<<F("Stopped")<<endl; debugSerial<<F("Stopped")<<endl;
@@ -217,22 +224,30 @@ debugSerial<<F("Deleting conf. RAM was:")<<freeRam();
bool isNotRetainingStatus() { bool isNotRetainingStatus() {
return (lanStatus != RETAINING_COLLECTING); return (lanStatus != RETAINING_COLLECTING);
} }
// Custom HTTP request handler
// Return values:
// 1 - work completed. Dont need to respond, just close socket
// 0 - no match continue with default lib behavior
// 401 - not authorized
// 400 - bad request
// 200 | CONTENT_TYPE - ok + content_type
// ... same sor other http codes
// if response != "" - put response in http answer
int httpHandler(Client& client, String request, long contentLength, bool authorized) uint16_t httpHandler(Client& client, String request, long contentLength, bool authorized, String& response )
{ {
String response = ""; //String response = "";
debugSerial<<request<<endl; debugSerial<<request<<endl;
if (request == (F("GET /"))) if (request == (F("GET /")))
{ {
client.println(F("HTTP/1.1 301 Moved permanently")); ArduinoOTA.sendHttpResponse(client,301,false); // Send only HTTP header, no close socket
client.print(F("Location: http://lazyhome.ru/pwa?mac=")); client.println(F("Location: http://lazyhome.ru/pwa?mac="));
for (int i=0; i<6; i++) {client.print(sysConf.mac[i]>>4,HEX);client.print(sysConf.mac[i]&0xf,HEX);} // todo for (int i=0; i<6; i++) {response+=(sysConf.mac[i]>>4,HEX);response+=(sysConf.mac[i]&0xf,HEX);}
client.print(F("&ip=")); //response+=(F("&ip="));
client.println(Ethernet.localIP()); //todo response+=(Ethernet.localIP());
client.println();
delay(100); delay(100);
client.stop();
return 1; return 1;
} }
if (!authorized) return 401; if (!authorized) return 401;
@@ -248,6 +263,7 @@ int httpHandler(Client& client, String request, long contentLength, bool authori
ic.loadItem(&item,SEND_COMMAND|SEND_PARAMETERS); ic.loadItem(&item,SEND_COMMAND|SEND_PARAMETERS);
char buf[32]; char buf[32];
response=ic.toString(buf, sizeof(buf)); response=ic.toString(buf, sizeof(buf));
return 200 | HTTP_TEXT_PLAIN;
} }
else if (request.startsWith(F("GET /item/"))) else if (request.startsWith(F("GET /item/")))
{ {
@@ -261,6 +277,7 @@ int httpHandler(Client& client, String request, long contentLength, bool authori
{if (item.isActive()) item.setCmd(CMD_ON); else item.setCmd(CMD_OFF);} {if (item.isActive()) item.setCmd(CMD_ON); else item.setCmd(CMD_OFF);}
char buf[32]; char buf[32];
response=ic.toString(buf, sizeof(buf)); response=ic.toString(buf, sizeof(buf));
return 200 | HTTP_TEXT_PLAIN;
} }
else if (request.startsWith(F("POST /command/"))) else if (request.startsWith(F("POST /command/")))
@@ -275,25 +292,9 @@ int httpHandler(Client& client, String request, long contentLength, bool authori
if (request=="reboot ") client.stop(); if (request=="reboot ") client.stop();
const char* res=request.c_str(); const char* res=request.c_str();
cmd_parse((char*) res); cmd_parse((char*) res);
return 200 | HTTP_TEXT_PLAIN;
} }
else return -1; //Unknown else return 0; //Unknown
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Connection: close"));
#ifdef CORS
client.print(F("Access-Control-Allow-Origin: "));
client.println(F(CORS));
#endif
if (response!="") {
client.println(F("Content-Type: text/plain"));
client.println();
client.println(response);
}
delay(100);
return 1;
} }
int inTopic (char * topic, topicType tt) int inTopic (char * topic, topicType tt)
@@ -410,7 +411,7 @@ if (element && element->type == aJson_String) return element->valuestring;
} }
debugSerial<<passwordBuf<<endl; debugSerial<<passwordBuf<<endl;
ArduinoOTA.begin(Ethernet.localIP(), "Lighthub", passwordBuf, InternalStorage, sysConfStream, JSONStream); ArduinoOTA.begin(Ethernet.localIP(), "Lighthub", passwordBuf, InternalStorage, sysConfStream);
ArduinoOTA.setCustomHandler(httpHandler); ArduinoOTA.setCustomHandler(httpHandler);
infoSerial<<F("OTA initialized\n"); infoSerial<<F("OTA initialized\n");
@@ -623,7 +624,7 @@ lan_status lanLoop() {
case DHCP_CHECK_REBIND_FAIL: case DHCP_CHECK_REBIND_FAIL:
errorSerial<<F("Error: rebind fail")<<endl; errorSerial<<F("Error: rebind fail")<<endl;
if (mqttClient.connected()) mqttClient.disconnect(); /// if (mqttClient.connected()) mqttClient.disconnect(); ??
//timerLanCheckTime = millis();// + 1000; //timerLanCheckTime = millis();// + 1000;
lanStatus = DO_REINIT; lanStatus = DO_REINIT;
break; break;
@@ -999,7 +1000,7 @@ void Changed(int i, DeviceAddress addr, float currentTemp) {
//char addrbuf[17]; //char addrbuf[17];
//char valstr[16] = "NIL"; //char valstr[16] = "NIL";
//char *owEmitString = NULL; //char *owEmitString = NULL;
char *owItem = NULL; //char *owItem = NULL;
SetBytes(addr, 8, addrstr); SetBytes(addr, 8, addrstr);
addrstr[17] = 0; addrstr[17] = 0;
@@ -1229,14 +1230,21 @@ int loadConfigFromEEPROM()
{ {
char ch; char ch;
infoSerial<<F("Loading Config from EEPROM")<<endl; infoSerial<<F("Loading Config from EEPROM")<<endl;
JSONStream.open('r'); #if defined(FS_STORAGE)
JSONStream.seek(); sysConfStream.open("/config.json",'r');
if (JSONStream.peek() == '{') { #else
aJsonStream as = aJsonStream(&JSONStream); sysConfStream.open(FN_CONFIG_JSON,'r');
#endif
//JSONStream.seek();
if (sysConfStream.peek() == '{') {
aJsonStream as = aJsonStream(&sysConfStream);
cleanConf(); cleanConf();
root = aJson.parse(&as); root = aJson.parse(&as);
sysConfStream.close();
if (!root) { if (!root) {
errorSerial<<F("load failed")<<endl; errorSerial<<F("load failed")<<endl;
// sysConfStream.close();
return 0; return 0;
} }
infoSerial<<F("Loaded")<<endl; infoSerial<<F("Loaded")<<endl;
@@ -1244,8 +1252,9 @@ int loadConfigFromEEPROM()
ethClient.stop(); //Refresh MQTT connect to get retained info ethClient.stop(); //Refresh MQTT connect to get retained info
return 1; return 1;
} else { } else {
JSONStream.write(255); //truncate garbage sysConfStream.putEOF(); //truncate garbage
infoSerial<<F("No stored config")<<endl; infoSerial<<F("No stored config")<<endl;
sysConfStream.close();
return 0; return 0;
} }
return 0; return 0;
@@ -1260,10 +1269,17 @@ if (arg_cnt>1)
infoSerial<<F("Config autosave:")<<sysConf.getSaveSuccedConfig()<<endl; infoSerial<<F("Config autosave:")<<sysConf.getSaveSuccedConfig()<<endl;
return; return;
} }
#if defined(FS_STORAGE)
sysConfStream.open("/config.json",'w');
#else
sysConfStream.open(FN_CONFIG_JSON,'w');
#endif
#if defined(__SAM3X8E__) #if defined(__SAM3X8E__)
char* outBuf = (char*) malloc(MAX_JSON_CONF_SIZE); /* XXX: Dynamic size. */ char* outBuf = (char*) malloc(MAX_JSON_CONF_SIZE); /* XXX: Dynamic size. */
if (outBuf == NULL) if (outBuf == NULL)
{ {
sysConfStream.close();
return; return;
} }
infoSerial<<F("Saving config to EEPROM..")<<endl; infoSerial<<F("Saving config to EEPROM..")<<endl;
@@ -1271,18 +1287,18 @@ if (arg_cnt>1)
aJson.print(root, &stringStream); aJson.print(root, &stringStream);
int len = strlen(outBuf); int len = strlen(outBuf);
outBuf[len++]= 255; outBuf[len++]= 255;
JSONStream.seek(); //JSONStream.seek();
size_t res = JSONStream.write((byte*) outBuf,len); size_t res = sysConfStream.write((byte*) outBuf,len);
free (outBuf); free (outBuf);
infoSerial<<res<< F("bytes from ")<<len<<F(" are saved to EEPROM")<<endl; infoSerial<<res<< F("bytes from ")<<len<<F(" are saved to EEPROM")<<endl;
#else #else
JSONStream.open('w'); //JSONStream.open('w');
JSONStream.seek(); //JSONStream.seek();
aJsonStream jsonEEPROMStream = aJsonStream(&JSONStream); aJsonStream jsonEEPROMStream = aJsonStream(&sysConfStream);
infoSerial<<F("Saving config to EEPROM.."); infoSerial<<F("Saving config to EEPROM..");
aJson.print(root, &jsonEEPROMStream); aJson.print(root, &jsonEEPROMStream);
JSONStream.putEOF(); sysConfStream.putEOF();
JSONStream.flush(); sysConfStream.close();
infoSerial<<F("Saved to EEPROM")<<endl; infoSerial<<F("Saved to EEPROM")<<endl;
#endif #endif
} }
@@ -1394,10 +1410,11 @@ void cmdFunctionSetMac(int arg_cnt, char **args) {
void cmdFunctionGet(int arg_cnt, char **args) { void cmdFunctionGet(int arg_cnt, char **args) {
if (arg_cnt>1) if (arg_cnt>1)
{ {
if (!strcasecmp_P(args[1],ON_P)) sysConf.setLoadHTTPConfig(true); if (!strcasecmp_P(args[1],ON_P)) {sysConf.setLoadHTTPConfig(true); return;};
if (!strcasecmp_P(args[1],OFF_P)) sysConf.setLoadHTTPConfig(false); if (!strcasecmp_P(args[1],OFF_P)) {sysConf.setLoadHTTPConfig(false); return;};
infoSerial<<F("Loading HTTP config on startup:")<<sysConf.getLoadHTTPConfig()<<endl; infoSerial<<F("Loading HTTP config on startup:")<<sysConf.getLoadHTTPConfig()<<endl;
return;
} }
lanStatus= loadConfigFromHttp(arg_cnt, args); lanStatus= loadConfigFromHttp(arg_cnt, args);

27
lighthub/seekablestream.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef _SEEKABLESTREAM_H_
#define _SEEKABLESTREAM_H_
#include <Stream.h>
#include <Arduino.h>
#define EOFchar 255
class seekableStream : public Stream
{
protected:
unsigned int streamSize;
bool textMode;
uint16_t contentType;
public:
seekableStream(unsigned int size):Stream(),streamSize(size) {};
unsigned int getSize() {return streamSize;}
void setSize (unsigned int size) {streamSize = size;};
virtual unsigned int seek(unsigned int _pos = 0) = 0;
virtual int open(String _filename, char mode) = 0;
virtual void close() = 0;
virtual uint16_t getContentType() {return contentType;};
virtual void putEOF() {if (textMode) write (EOFchar);};
};
#endif

View File

@@ -0,0 +1,48 @@
#define SYSCONF_OFFSET 0
#define EEPROM_offset_NotAlligned SYSCONF_OFFSET+sizeof(systemConfigData)
#define SYSCONF_SIZE EEPROM_offsetJSON
#define EEPROM_offsetJSON EEPROM_offset_NotAlligned + (4 -(EEPROM_offset_NotAlligned & 3))
#define MAXFLASHSTR 32
#define PWDFLASHSTR 16
#define EEPROM_SIGNATURE "LHCF"
#define EEPROM_SIGNATURE_LENGTH 4
//#define EEPROM_offsetJSON IFLASH_PAGE_SIZE
#define EEPROM_FIX_PART_LEN EEPROM_offsetJSON-SYSCONF_OFFSET
const char EEPROM_signature[] = EEPROM_SIGNATURE;
typedef char flashstr[MAXFLASHSTR];
typedef char flashpwd[PWDFLASHSTR];
typedef uint8_t macAddress[6];
#pragma pack(push, 1)
typedef struct
{
char signature[4];
macAddress mac; //6 bytes
union {
uint16_t configFlags;
struct
{
uint8_t serialDebugLevel:4;
uint8_t syslogDebugLevel:4;
uint8_t notGetConfigFromHTTP:1;
uint8_t saveToFlash:1;
};
};
uint32_t ip;
uint32_t dns;
uint32_t gw;
uint32_t mask;
flashstr configURL;
flashpwd MQTTpwd;
flashpwd OTApwd;
uint16_t sysConfigHash;
uint16_t JSONHash;
} systemConfigData;
#pragma (pop)