Browse Source

added ESP8266 code

pull/4/head
lumapu 3 years ago
parent
commit
5f927ad8c5
  1. 158
      tools/esp8266/CircularBuffer.h
  2. 45
      tools/esp8266/README.md
  3. 25
      tools/esp8266/ahoy-esp.ino
  4. 265
      tools/esp8266/app.cpp
  5. 50
      tools/esp8266/app.h
  6. 37
      tools/esp8266/defines.h
  7. 130
      tools/esp8266/eep.cpp
  8. 30
      tools/esp8266/eep.h
  9. 228
      tools/esp8266/hoymiles.h
  10. 4
      tools/esp8266/html/conv.bat
  11. 1
      tools/esp8266/html/h/index_html.h
  12. 1
      tools/esp8266/html/h/setup_html.h
  13. 1
      tools/esp8266/html/h/style_css.h
  14. 45
      tools/esp8266/html/index.html
  15. 51
      tools/esp8266/html/setup.html
  16. 151
      tools/esp8266/html/style.css
  17. 340
      tools/esp8266/main.cpp
  18. 79
      tools/esp8266/main.h
  19. BIN
      tools/esp8266/tools/fileConv.exe

158
tools/esp8266/CircularBuffer.h

@ -0,0 +1,158 @@
/*
CircularBuffer - An Arduino circular buffering library for arbitrary types.
Created by Ivo Pullens, Emmission, 2014 -- www.emmission.nl
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CircularBuffer_h
#define CircularBuffer_h
#ifdef ESP8266
#define DISABLE_IRQ noInterrupts()
#define RESTORE_IRQ interrupts()
#else
#define DISABLE_IRQ \
uint8_t sreg = SREG; \
cli();
#define RESTORE_IRQ \
SREG = sreg;
#endif
template <class T> class CircularBuffer
{
public:
/** Constructor
* @param buffer Preallocated buffer of at least size records.
* @param size Number of records available in the buffer.
*/
CircularBuffer(T* buffer, const uint8_t size )
: m_size(size), m_buff(buffer)
{
clear();
}
/** Clear all entries in the circular buffer. */
void clear(void)
{
m_front = 0;
m_fill = 0;
}
/** Test if the circular buffer is empty */
inline bool empty(void) const
{
return !m_fill;
}
/** Return the number of records stored in the buffer */
inline uint8_t available(void) const
{
return m_fill;
}
/** Test if the circular buffer is full */
inline bool full(void) const
{
return m_fill == m_size;
}
/** Aquire record on front of the buffer, for writing.
* After filling the record, it has to be pushed to actually
* add it to the buffer.
* @return Pointer to record, or NULL when buffer is full.
*/
T* getFront(void) const
{
DISABLE_IRQ;
T* f = NULL;
if (!full())
f = get(m_front);
RESTORE_IRQ;
return f;
}
/** Push record to front of the buffer
* @param record Record to push. If record was aquired previously (using getFront) its
* data will not be copied as it is already present in the buffer.
* @return True, when record was pushed successfully.
*/
bool pushFront(T* record)
{
bool ok = false;
DISABLE_IRQ;
if (!full())
{
T* f = get(m_front);
if (f != record)
*f = *record;
m_front = (m_front+1) % m_size;
m_fill++;
ok = true;
}
RESTORE_IRQ;
return ok;
}
/** Aquire record on back of the buffer, for reading.
* After reading the record, it has to be pop'ed to actually
* remove it from the buffer.
* @return Pointer to record, or NULL when buffer is empty.
*/
T* getBack(void) const
{
T* b = NULL;
DISABLE_IRQ;
if (!empty())
b = get(back());
RESTORE_IRQ;
return b;
}
/** Remove record from back of the buffer.
* @return True, when record was pop'ed successfully.
*/
bool popBack(void)
{
bool ok = false;
DISABLE_IRQ;
if (!empty())
{
m_fill--;
ok = true;
}
RESTORE_IRQ;
return ok;
}
protected:
inline T * get(const uint8_t idx) const
{
return &(m_buff[idx]);
}
inline uint8_t back(void) const
{
return (m_front - m_fill + m_size) % m_size;
}
const uint8_t m_size; // Total number of records that can be stored in the buffer.
T* const m_buff; // Ptr to buffer holding all records.
volatile uint8_t m_front; // Index of front element (not pushed yet).
volatile uint8_t m_fill; // Amount of records currently pushed.
};
#endif // CircularBuffer_h

45
tools/esp8266/README.md

@ -0,0 +1,45 @@
## OVERVIEW
This code was tested on a ESP8266 - ESP-07 module. Many parts of the code are based on 'Hubi's code, which can be found here: <https://www.mikrocontroller.net/topic/525778?page=3#7033371>
The NRF24L01+ radio module is connected to the standard SPI pins. Additional there are 3 pins, which can be set individual:
- IRQ - Pin 4
- CE - Pin 5
- CS - Pin 15
## Compile
This code can be compiled using Arduino. The settings were:
- Board: Generic ESP8266 Module
- Flash-Size: 1MB (FS: none, OTA: 502kB)
## Flash ESP with firmware
1. flash the ESP with the compiled firmware using the UART pins or any preinstalled firmware with OTA capabilities
2. repower the ESP
3. the ESP will start as access point (AP) if there is no network config stored in its eeprom
4. connect to the AP, you will be forwarded to the setup page
5. configure your WiFi settings, save, repower
6. check your router for the IP address of the module
## Usage
Connect the ESP to power and to your serial console. The webinterface is currently only used for OTA and config.
The serial console will print all information which is send and received.
## Known Issues
- only command 0x81 is received
## USED LIBRARIES
- `Time`
- `RF24`

25
tools/esp8266/ahoy-esp.ino

@ -0,0 +1,25 @@
#include "app.h"
app myApp;
//-----------------------------------------------------------------------------
void setup() {
pinMode(RF24_IRQ_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RF24_IRQ_PIN), handleIntr, FALLING);
// AP name, password, timeout
myApp.setup("ESP AHOY", "esp_8266", 15);
}
//-----------------------------------------------------------------------------
void loop() {
myApp.loop();
}
//-----------------------------------------------------------------------------
ICACHE_RAM_ATTR void handleIntr(void) {
myApp.handleIntr();
}

265
tools/esp8266/app.cpp

@ -0,0 +1,265 @@
#include "app.h"
#include "html/h/index_html.h"
extern String setup_html;
//-----------------------------------------------------------------------------
app::app() : Main() {
uint8_t wrAddr[6];
mRadio = new RF24(RF24_CE_PIN, RF24_CS_PIN);
mRadio->begin();
mRadio->setAutoAck(false);
mRadio->setRetries(0, 0);
mHoymiles = new hoymiles();
mEep->read(ADDR_HOY_ADDR, mHoymiles->mAddrBytes, HOY_ADDR_LEN);
mHoymiles->serial2RadioId();
mBufCtrl = new CircularBuffer(mBuffer, PACKET_BUFFER_SIZE);
mSendCnt = 0;
mSendTicker = new Ticker();
}
//-----------------------------------------------------------------------------
app::~app(void) {
}
//-----------------------------------------------------------------------------
void app::setup(const char *ssid, const char *pwd, uint32_t timeout) {
Main::setup(ssid, pwd, timeout);
mWeb->on("/", std::bind(&app::showIndex, this));
mWeb->on("/setup", std::bind(&app::showSetup, this));
mWeb->on("/save ", std::bind(&app::showSave, this));
initRadio();
mSendTicker->attach_ms(1000, std::bind(&app::sendTicker, this));
}
//-----------------------------------------------------------------------------
void app::loop(void) {
Main::loop();
if(!mBufCtrl->empty()) {
uint8_t len, rptCnt;
NRF24_packet_t *p = mBufCtrl->getBack();
//mHoymiles->dumpBuf("RAW", p->packet, PACKET_BUFFER_SIZE);
if(mHoymiles->checkCrc(p->packet, &len, &rptCnt)) {
// process buffer only on first occurrence
if((0 != len) && (0 == rptCnt)) {
mHoymiles->dumpBuf("Payload", p->packet, len);
// @TODO: do analysis here
}
}
else {
if(p->packetsLost != 0) {
Serial.println("Lost packets: " + String(p->packetsLost));
}
}
mBufCtrl->popBack();
}
}
//-----------------------------------------------------------------------------
void app::handleIntr(void) {
uint8_t lostCnt = 0, pipe, len;
NRF24_packet_t *p;
DISABLE_IRQ;
while(mRadio->available(&pipe)) {
if(!mBufCtrl->full()) {
p = mBufCtrl->getFront();
memset(p->packet, 0xcc, MAX_RF_PAYLOAD_SIZE);
p->timestamp = micros(); // Micros does not increase in interrupt, but it can be used.
p->packetsLost = lostCnt;
len = mRadio->getPayloadSize();
if(len > MAX_RF_PAYLOAD_SIZE)
len = MAX_RF_PAYLOAD_SIZE;
mRadio->read(p->packet, len);
mBufCtrl->pushFront(p);
lostCnt = 0;
}
else {
bool tx_ok, tx_fail, rx_ready;
if(lostCnt < 255)
lostCnt++;
mRadio->whatHappened(tx_ok, tx_fail, rx_ready); // reset interrupt status
mRadio->flush_rx(); // drop the packet
}
}
RESTORE_IRQ;
}
//-----------------------------------------------------------------------------
void app::initRadio(void) {
mRadio->setChannel(DEFAULT_RECV_CHANNEL);
mRadio->setDataRate(RF24_250KBPS);
mRadio->disableCRC();
mRadio->setAutoAck(false);
mRadio->setPayloadSize(MAX_RF_PAYLOAD_SIZE);
mRadio->setAddressWidth(5);
mRadio->openReadingPipe(1, DTU_RADIO_ID);
// enable only receiving interrupts
mRadio->maskIRQ(true, true, false);
// Use lo PA level, as a higher level will disturb CH340 serial usb adapter
mRadio->setPALevel(RF24_PA_MAX);
mRadio->startListening();
Serial.println("Radio Config:");
mRadio->printPrettyDetails();
}
//-----------------------------------------------------------------------------
void app::sendPacket(uint8_t buf[], uint8_t len) {
DISABLE_IRQ;
mRadio->stopListening();
#ifdef CHANNEL_HOP
mRadio->setChannel(mHoymiles->getNxtChannel());
#else
mRadio->setChannel(mHoymiles->getDefaultChannel());
#endif
mRadio->openWritingPipe(mHoymiles->mRadioId);
mRadio->setCRCLength(RF24_CRC_16);
mRadio->enableDynamicPayloads();
mRadio->setAutoAck(true);
mRadio->setRetries(3, 15);
mRadio->write(buf, len);
// Try to avoid zero payload acks (has no effect)
mRadio->openWritingPipe(DUMMY_RADIO_ID);
mRadio->setAutoAck(false);
mRadio->setRetries(0, 0);
mRadio->disableDynamicPayloads();
mRadio->setCRCLength(RF24_CRC_DISABLED);
mRadio->setChannel(DEFAULT_RECV_CHANNEL);
mRadio->startListening();
RESTORE_IRQ;
}
//-----------------------------------------------------------------------------
void app::sendTicker(void) {
uint8_t size = 0;
if((mSendCnt % 6) == 0)
size = mHoymiles->getTimePacket(mSendBuf, mTimestamp);
else if((mSendCnt % 6) == 5)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x81);
else if((mSendCnt % 6) == 4)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x80);
else if((mSendCnt % 6) == 3)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x83);
else if((mSendCnt % 6) == 2)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x82);
else if((mSendCnt % 6) == 1)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x84);
Serial.println("sent packet: #" + String(mSendCnt));
dumpBuf(mSendBuf, size);
sendPacket(mSendBuf, size);
mSendCnt++;
}
//-----------------------------------------------------------------------------
void app::showIndex(void) {
String html = index_html;
html.replace("{DEVICE}", mDeviceName);
html.replace("{VERSION}", mVersion);
mWeb->send(200, "text/html", html);
}
//-----------------------------------------------------------------------------
void app::showSetup(void) {
// overrides same method in main.cpp
String html = setup_html;
html.replace("{SSID}", mStationSsid);
// PWD will be left at the default value (for protection)
// -> the PWD will only be changed if it does not match the placeholder "{PWD}"
char addr[20] = {0};
sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X", mHoymiles->mAddrBytes[0], mHoymiles->mAddrBytes[1], mHoymiles->mAddrBytes[2], mHoymiles->mAddrBytes[3], mHoymiles->mAddrBytes[4], mHoymiles->mAddrBytes[5]);
html.replace("{HOY_ADDR}", String(addr));
html.replace("{DEVICE}", String(mDeviceName));
html.replace("{VERSION}", String(mVersion));
mWeb->send(200, "text/html", html);
}
//-----------------------------------------------------------------------------
void app::showSave(void) {
saveValues(true);
}
//-----------------------------------------------------------------------------
void app::saveValues(bool webSend = true) {
Main::saveValues(false); // general configuration
if(mWeb->args() > 0) {
char *p;
char addr[20] = {0};
uint8_t i = 0;
memset(mHoymiles->mAddrBytes, 0, 6);
mWeb->arg("hoy_addr").toCharArray(addr, 20);
p = strtok(addr, ":");
while(NULL != p) {
mHoymiles->mAddrBytes[i++] = strtol(p, NULL, 16);
p = strtok(NULL, ":");
}
mEep->write(ADDR_HOY_ADDR, mHoymiles->mAddrBytes, HOY_ADDR_LEN);
if((mWeb->arg("reboot") == "on"))
showReboot();
else {
mWeb->send(200, "text/html", "<!doctype html><html><head><title>Setup saved</title><meta http-equiv=\"refresh\" content=\"0; URL=/setup\"></head><body>"
"<p>saved</p></body></html>");
}
}
else {
mWeb->send(200, "text/html", "<!doctype html><html><head><title>Error</title><meta http-equiv=\"refresh\" content=\"3; URL=/setup\"></head><body>"
"<p>Error while saving</p></body></html>");
}
}
//-----------------------------------------------------------------------------
void app::dumpBuf(uint8_t buf[], uint8_t len) {
for(uint8_t i = 0; i < len; i ++) {
if((i % 8 == 0) && (i != 0))
Serial.println();
Serial.print(String(buf[i], HEX) + " ");
}
Serial.println();
}

50
tools/esp8266/app.h

@ -0,0 +1,50 @@
#ifndef __APP_H__
#define __APP_H__
#include <RF24.h>
#include <RF24_config.h>
#include "defines.h"
#include "main.h"
#include "CircularBuffer.h"
#include "hoymiles.h"
class app : public Main {
public:
app();
~app();
void setup(const char *ssid, const char *pwd, uint32_t timeout);
void loop(void);
void handleIntr(void);
private:
void initRadio(void);
void sendPacket(uint8_t data[], uint8_t length);
void sendTicker(void);
void showIndex(void);
void showSetup(void);
void showSave(void);
void saveValues(bool webSend);
void dumpBuf(uint8_t buf[], uint8_t len);
uint8_t mState;
bool mKeyPressed;
RF24 *mRadio;
hoymiles *mHoymiles;
CircularBuffer<NRF24_packet_t> *mBufCtrl;
NRF24_packet_t mBuffer[PACKET_BUFFER_SIZE];
Ticker *mSendTicker;
uint32_t mSendCnt;
uint8_t mSendBuf[MAX_RF_PAYLOAD_SIZE];
};
#endif /*__APP_H__*/

37
tools/esp8266/defines.h

@ -0,0 +1,37 @@
#ifndef __DEFINES_H__
#define __DEFINES_H__
//-------------------------------------
// PINOUT
//-------------------------------------
#define RF24_IRQ_PIN 4
#define RF24_CE_PIN 5
#define RF24_CS_PIN 15
//-------------------------------------
// VERSION
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 1
#define VERSION_PATCH 7
//-------------------------------------
// EEPROM
//-------------------------------------
#define SSID_LEN 32
#define PWD_LEN 64
#define DEVNAME_LEN 32
#define HOY_ADDR_LEN 6
#define ADDR_SSID 0 // start address
#define ADDR_PWD ADDR_SSID + SSID_LEN
#define ADDR_DEVNAME ADDR_PWD + PWD_LEN
#define ADDR_HOY_ADDR ADDR_DEVNAME + DEVNAME_LEN
#endif /*__DEFINES_H__*/

130
tools/esp8266/eep.cpp

@ -0,0 +1,130 @@
#include "eep.h"
#include <EEPROM.h>
//-----------------------------------------------------------------------------
eep::eep() {
EEPROM.begin(500);
}
//-----------------------------------------------------------------------------
eep::~eep() {
EEPROM.end();
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, char *str, uint8_t length) {
for(uint8_t i = 0; i < length; i ++) {
*(str++) = (char)EEPROM.read(addr++);
}
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, float *value) {
uint8_t *p = (uint8_t*)value;
for(uint8_t i = 0; i < 4; i ++) {
*(p++) = (uint8_t)EEPROM.read(addr++);
}
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, bool *value) {
uint8_t intVal = 0x00;
intVal = EEPROM.read(addr++);
*value = (intVal == 0x01);
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, uint8_t *value) {
*value = (EEPROM.read(addr++));
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, uint8_t data[], uint8_t length) {
for(uint8_t i = 0; i < length; i ++) {
*(data++) = EEPROM.read(addr++);
}
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, uint16_t *value) {
*value = (EEPROM.read(addr++) << 8);
*value |= (EEPROM.read(addr++));
}
//-----------------------------------------------------------------------------
void eep::read(uint32_t addr, uint32_t *value) {
*value = (EEPROM.read(addr++) << 24);
*value |= (EEPROM.read(addr++) << 16);
*value |= (EEPROM.read(addr++) << 8);
*value |= (EEPROM.read(addr++));
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, const char *str, uint8_t length) {
for(uint8_t i = 0; i < length; i ++) {
EEPROM.write(addr++, str[i]);
}
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, uint8_t data[], uint8_t length) {
for(uint8_t i = 0; i < length; i ++) {
EEPROM.write(addr++, data[i]);
}
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, float value) {
uint8_t *p = (uint8_t*)&value;
for(uint8_t i = 0; i < 4; i ++) {
EEPROM.write(addr++, p[i]);
}
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, bool value) {
uint8_t intVal = (value) ? 0x01 : 0x00;
EEPROM.write(addr++, intVal);
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, uint8_t value) {
EEPROM.write(addr++, value);
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, uint16_t value) {
EEPROM.write(addr++, (value >> 8) & 0xff);
EEPROM.write(addr++, (value ) & 0xff);
EEPROM.commit();
}
//-----------------------------------------------------------------------------
void eep::write(uint32_t addr, uint32_t value) {
EEPROM.write(addr++, (value >> 24) & 0xff);
EEPROM.write(addr++, (value >> 16) & 0xff);
EEPROM.write(addr++, (value >> 8) & 0xff);
EEPROM.write(addr++, (value ) & 0xff);
EEPROM.commit();
}

30
tools/esp8266/eep.h

@ -0,0 +1,30 @@
#ifndef __EEP_H__
#define __EEP_H__
#include "Arduino.h"
class eep {
public:
eep();
~eep();
void read(uint32_t addr, char *str, uint8_t length);
void read(uint32_t addr, float *value);
void read(uint32_t addr, bool *value);
void read(uint32_t addr, uint8_t *value);
void read(uint32_t addr, uint8_t data[], uint8_t length);
void read(uint32_t addr, uint16_t *value);
void read(uint32_t addr, uint32_t *value);
void write(uint32_t addr, const char *str, uint8_t length);
void write(uint32_t addr, uint8_t data[], uint8_t length);
void write(uint32_t addr, float value);
void write(uint32_t addr, bool value);
void write(uint32_t addr, uint8_t value);
void write(uint32_t addr, uint16_t value);
void write(uint32_t addr, uint32_t value);
private:
};
#endif /*__EEP_H__*/

228
tools/esp8266/hoymiles.h

@ -0,0 +1,228 @@
#ifndef __HOYMILES_H__
#define __HOYMILES_H__
#include <RF24.h>
#include <RF24_config.h>
#define CHANNEL_HOP // switch between channels or use static channel to send
#define luint64_t long long unsigned int
#define DEFAULT_RECV_CHANNEL 3
#define MAX_RF_PAYLOAD_SIZE 32
#define DTU_RADIO_ID ((uint64_t)0x1234567801ULL)
#define DUMMY_RADIO_ID ((uint64_t)0xDEADBEEF01ULL)
#define PACKET_BUFFER_SIZE 30
#define CRC8_INIT 0x00
#define CRC8_POLY 0x01
#define CRC16_MODBUS_POLYNOM 0xA001
#define CRC16_NRF24_POLYNOM 0x1021
//-----------------------------------------------------------------------------
// MACROS
#define CP_U32_LittleEndian(buf, v) ({ \
uint8_t *b = buf; \
b[0] = ((v >> 24) & 0xff); \
b[1] = ((v >> 16) & 0xff); \
b[2] = ((v >> 8) & 0xff); \
b[3] = ((v ) & 0xff); \
})
#define CP_U32_BigEndian(buf, v) ({ \
uint8_t *b = buf; \
b[3] = ((v >> 24) & 0xff); \
b[2] = ((v >> 16) & 0xff); \
b[1] = ((v >> 8) & 0xff); \
b[0] = ((v ) & 0xff); \
})
#define BIT_CNT(x) ((x)<<3)
//-----------------------------------------------------------------------------
union uint64Bytes {
uint64_t ull;
uint8_t bytes[8];
};
typedef struct {
uint32_t timestamp;
uint8_t packetsLost;
uint8_t packet[MAX_RF_PAYLOAD_SIZE];
} NRF24_packet_t;
//-----------------------------------------------------------------------------
class hoymiles {
public:
hoymiles() {
serial2RadioId();
calcDtuIdCrc();
mChannels = new uint8_t(4);
mChannels[0] = 23;
mChannels[1] = 40;
mChannels[2] = 61;
mChannels[3] = 75;
mChanIdx = 1;
mLastCrc = 0x0000;
mRptCnt = 0;
}
~hoymiles() {}
uint8_t getDefaultChannel(void) {
return mChannels[1];
}
uint8_t getNxtChannel(void) {
if(++mChanIdx >= 4)
mChanIdx = 0;
return mChannels[mChanIdx];
}
void serial2RadioId(void) {
uint64Bytes id;
id.ull = 0ULL;
id.bytes[4] = mAddrBytes[5];
id.bytes[3] = mAddrBytes[4];
id.bytes[2] = mAddrBytes[3];
id.bytes[1] = mAddrBytes[2];
id.bytes[0] = 0x01;
mRadioId = id.ull;
}
uint8_t getTimePacket(uint8_t buf[], uint32_t ts) {
memset(buf, 0, MAX_RF_PAYLOAD_SIZE);
buf[0] = 0x15;
CP_U32_BigEndian(&buf[1], (mRadioId >> 8));
CP_U32_BigEndian(&buf[5], (DTU_RADIO_ID >> 8));
buf[9] = 0x00;
buf[10] = 0x0b; // cid
buf[11] = 0x00;
CP_U32_LittleEndian(&buf[12], ts);
buf[19] = 0x05;
uint16_t crc = crc16(&buf[10], 14);
buf[24] = (crc >> 8) & 0xff;
buf[25] = (crc ) & 0xff;
buf[26] = crc8(buf, 26);
return 27;
}
uint8_t getCmdPacket(uint8_t buf[], uint8_t mid, uint8_t cmd) {
buf[0] = mid;
CP_U32_BigEndian(&buf[1], (mRadioId >> 8));
CP_U32_BigEndian(&buf[5], (DTU_RADIO_ID >> 8));
buf[9] = cmd;
buf[10] = crc8(buf, 10);
return 11;
}
bool checkCrc(uint8_t buf[], uint8_t *len, uint8_t *rptCnt) {
*len = (buf[0] >> 2);
for (int16_t i = MAX_RF_PAYLOAD_SIZE - 1; i >= 0; i--) {
buf[i] = ((buf[i] >> 7) | ((i > 0) ? (buf[i-1] << 1) : 0x00));
}
uint16_t crc = crc16nrf24(buf, BIT_CNT(*len + 2), 7, mDtuIdCrc);
bool valid = (crc == ((buf[*len+2] << 8) | (buf[*len+3])));
if(valid) {
if(mLastCrc == crc)
*rptCnt = (++mRptCnt);
else {
mRptCnt = 0;
*rptCnt = 0;
mLastCrc = crc;
}
}
return valid;
}
void dumpBuf(const char *info, uint8_t buf[], uint8_t len) {
Serial.print(String(info));
for(uint8_t i = 0; i < len; i++) {
Serial.print(buf[i], HEX);
Serial.print(" ");
}
Serial.println();
}
uint8_t mAddrBytes[6];
luint64_t mRadioId;
private:
void calcDtuIdCrc(void) {
uint64_t addr = DTU_RADIO_ID;
uint8_t dtuAddr[5];
for(int8_t i = 4; i >= 0; i--) {
dtuAddr[i] = addr;
addr >>= 8;
}
mDtuIdCrc = crc16nrf24(dtuAddr, BIT_CNT(5));
}
uint8_t crc8(uint8_t buf[], uint8_t len) {
uint8_t crc = CRC8_INIT;
for(uint8_t i = 0; i < len; i++) {
crc ^= buf[i];
for(uint8_t b = 0; b < 8; b ++) {
crc = (crc << 1) ^ ((crc & 0x80) ? CRC8_POLY : 0x00);
}
}
return crc;
}
uint16_t crc16(uint8_t buf[], uint8_t len) {
uint16_t crc = 0xffff;
uint8_t lsb;
for(uint8_t i = 0; i < len; i++) {
crc = crc ^ buf[i];
for(int8_t b = 7; b >= 0; b--) {
lsb = (crc & 0x0001);
if(lsb == 0x01)
crc--;
crc = crc >> 1;
if(lsb == 0x01)
crc = crc ^ CRC16_MODBUS_POLYNOM;
}
}
return crc;
}
uint16_t crc16nrf24(uint8_t buf[], uint16_t lenBits, uint16_t startBit = 0, uint16_t crcIn = 0xffff) {
uint16_t crc = crcIn;
uint8_t idx, val = buf[(startBit >> 3)];
for(uint16_t bit = startBit; bit < lenBits; bit ++) {
idx = bit & 0x07;
if(0 == idx)
val = buf[(bit >> 3)];
crc ^= 0x8000 & (val << (8 + idx));
crc = (crc & 0x8000) ? ((crc << 1) ^ CRC16_NRF24_POLYNOM) : (crc << 1);
}
return crc;
}
uint8_t *mChannels;
uint8_t mChanIdx;
uint16_t mDtuIdCrc;
uint16_t mLastCrc;
uint8_t mRptCnt;
};
#endif /*__HOYMILES_H__*/

4
tools/esp8266/html/conv.bat

@ -0,0 +1,4 @@
..\tools\fileConv.exe index.html h\index_html.h index_html
..\tools\fileConv.exe setup.html h\setup_html.h setup_html
..\tools\fileConv.exe style.css h\style_css.h style_css
pause

1
tools/esp8266/html/h/index_html.h

@ -0,0 +1 @@
String index_html = "<!doctype html><html><head><title>Index - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\"> window.setInterval(\"getAjax('/uptime', 'uptime')\", 1000); window.setInterval(\"getAjax('/time', 'time')\", 1000); function getAjax(url, resid) { var http = null; http = new XMLHttpRequest(); if(http != null) { http.open(\"GET\", url, true); http.onreadystatechange = print; http.send(null); } function print() { if(http.readyState == 4) { document.getElementById(resid).innerHTML = http.responseText; } } } </script></head><body><h1>AHOY - {DEVICE}</h1><div id=\"content\" class=\"content\"><p><a href=\"/update\">Update</a><br/><br/><a href=\"/setup\">Setup</a><br/><a href=\"/reboot\">Reboot</a></p><p><span class=\"des\">Uptime: </span><span id=\"uptime\"></span></p><p><span class=\"des\">Time: </span><span id=\"time\"></span></p></div><div id=\"footer\"><p class=\"left\">&copy 2022</p><p class=\"right\">AHOY :: {VERSION}</p></div></body></html>";

1
tools/esp8266/html/h/setup_html.h

@ -0,0 +1 @@
String setup_html = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><body><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p> Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"/save\"><p class=\"des\">WiFi</p><div class=\"inputWrp\"><input type=\"text\" class=\"inputText\" name=\"ssid\" value=\"{SSID}\" required/><span class=\"floating_label\">SSID</span></div><div class=\"inputWrp\"><input type=\"password\" class=\"inputText\" name=\"pwd\" value=\"{PWD}\" required/><span class=\"floating_label\">PASSWORD</span></div><p class=\"des\">Device Host Name</p><div class=\"inputWrp\"><input type=\"text\" class=\"inputText\" name=\"device\" value=\"{DEVICE}\" required/><span class=\"floating_label\">DEVICE NAME</span></div><p class=\"des\">General</p><div class=\"inputWrp\"><input type=\"text\" class=\"inputText\" name=\"hoy_addr\" value=\"{HOY_ADDR}\" required/><span class=\"floating_label\">HOYMILES ADDRESS (eg. 11:22:33:44:55:66)</span></div><input type=\"checkbox\" class=\"cb\" name=\"reboot\"/><label for=\"reboot\">Reboot device after successful save</label><input type=\"submit\" value=\"save\" class=\"button\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"/\">Home</a></p><p class=\"left\"><a href=\"/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p></div></body></html>";

1
tools/esp8266/html/h/style_css.h

@ -0,0 +1 @@
String style_css = "h1 { margin: 0; padding: 20pt; font-size: 22pt; color: #fff; background-color: #006ec0; display: block; text-transform: uppercase; } html, body { font-family: Arial; margin: 0; padding: 0; } p { text-align: justify; font-size: 13pt; } .des { font-size: 14pt; color: #006ec0; padding-bottom: 0px !important; } .fw { width: 60px; display: block; float: left; } .color { width: 50px; height: 50px; border: 1px solid #ccc; } .range { width: 300px; } a:link, a:visited { text-decoration: none; font-size: 13pt; color: #006ec0; } a:hover, a:focus { color: #f00; } #content { padding: 15px 15px 60px 15px; } #footer { position: fixed; bottom: 0px; height: 45px; background-color: #006ec0; width: 100%; } #footer p { color: #fff; padding-left: 20px; padding-right: 20px; font-size: 10pt !important; } #footer a { color: #fff; } #footer a:hover { color: #f00; } div.content { background-color: #fff; padding-bottom: 65px; overflow: hidden; } span.warn { display: inline-block; padding-left: 20px; color: #ff9900; font-style: italic; } input { padding: 10px; font-size: 13pt; } input.button { background-color: #006ec0; color: #fff; border: 0px; float: right; text-transform: uppercase; } input.cb { margin-bottom: 20px; } label { font-size: 14pt; } .left { float: left; } .right { float: right; } .inputWrp { position: relative; } .inputWrp .inputText { height: 35px; width: 90%; margin-bottom: 20px; border: 1px solid #ccc; border-top: none; border-right: none; } .inputWrp .floating_label { position: absolute; pointer-events: none; top: 20px; left: 10px; transition: 0.2s ease all; } .inputWrp input:focus ~ .floating_label, .inputWrp input:not(:focus):valid ~ .floating_label { top: 0px; left: 20px; font-size: 10px; color: blue; opacity: 1; } ";

45
tools/esp8266/html/index.html

@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<title>Index - {DEVICE}</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
window.setInterval("getAjax('/uptime', 'uptime')", 1000);
window.setInterval("getAjax('/time', 'time')", 1000);
function getAjax(url, resid) {
var http = null;
http = new XMLHttpRequest();
if(http != null) {
http.open("GET", url, true);
http.onreadystatechange = print;
http.send(null);
}
function print() {
if(http.readyState == 4) {
document.getElementById(resid).innerHTML = http.responseText;
}
}
}
</script>
</head>
<body>
<h1>AHOY - {DEVICE}</h1>
<div id="content" class="content">
<p>
<a href="/update">Update</a><br/>
<br/>
<a href="/setup">Setup</a><br/>
<a href="/reboot">Reboot</a>
</p>
<p><span class="des">Uptime: </span><span id="uptime"></span></p>
<p><span class="des">Time: </span><span id="time"></span></p>
</div>
<div id="footer">
<p class="left">&copy 2022</p>
<p class="right">AHOY :: {VERSION}</p>
</div>
</body>
</html>

51
tools/esp8266/html/setup.html

@ -0,0 +1,51 @@
<!doctype html>
<html>
<head>
<title>Setup - {DEVICE}</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Setup</h1>
<div id="setup" class="content">
<div id="content">
<p>
Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.
</p>
<form method="post" action="/save">
<p class="des">WiFi</p>
<div class="inputWrp">
<input type="text" class="inputText" name="ssid" value="{SSID}" required/>
<span class="floating_label">SSID</span>
</div>
<div class="inputWrp">
<input type="password" class="inputText" name="pwd" value="{PWD}" required/>
<span class="floating_label">PASSWORD</span>
</div>
<p class="des">Device Host Name</p>
<div class="inputWrp">
<input type="text" class="inputText" name="device" value="{DEVICE}" required/>
<span class="floating_label">DEVICE NAME</span>
</div>
<p class="des">General</p>
<div class="inputWrp">
<input type="text" class="inputText" name="hoy_addr" value="{HOY_ADDR}" required/>
<span class="floating_label">HOYMILES ADDRESS (eg. 11:22:33:44:55:66)</span>
</div>
<input type="checkbox" class="cb" name="reboot"/>
<label for="reboot">Reboot device after successful save</label>
<input type="submit" value="save" class="button" />
</form>
</div>
</div>
<div id="footer">
<p class="left"><a href="/">Home</a></p>
<p class="left"><a href="/update">Update Firmware</a></p>
<p class="right">AHOY - {VERSION}</p>
</div>
</body>
</html>

151
tools/esp8266/html/style.css

@ -0,0 +1,151 @@
h1 {
margin: 0;
padding: 20pt;
font-size: 22pt;
color: #fff;
background-color: #006ec0;
display: block;
text-transform: uppercase;
}
html, body {
font-family: Arial;
margin: 0;
padding: 0;
}
p {
text-align: justify;
font-size: 13pt;
}
.des {
font-size: 14pt;
color: #006ec0;
padding-bottom: 0px !important;
}
.fw {
width: 60px;
display: block;
float: left;
}
.color {
width: 50px;
height: 50px;
border: 1px solid #ccc;
}
.range {
width: 300px;
}
a:link, a:visited {
text-decoration: none;
font-size: 13pt;
color: #006ec0;
}
a:hover, a:focus {
color: #f00;
}
#content {
padding: 15px 15px 60px 15px;
}
#footer {
position: fixed;
bottom: 0px;
height: 45px;
background-color: #006ec0;
width: 100%;
}
#footer p {
color: #fff;
padding-left: 20px;
padding-right: 20px;
font-size: 10pt !important;
}
#footer a {
color: #fff;
}
#footer a:hover {
color: #f00;
}
div.content {
background-color: #fff;
padding-bottom: 65px;
overflow: hidden;
}
span.warn {
display: inline-block;
padding-left: 20px;
color: #ff9900;
font-style: italic;
}
input {
padding: 10px;
font-size: 13pt;
}
input.button {
background-color: #006ec0;
color: #fff;
border: 0px;
float: right;
text-transform: uppercase;
}
input.cb {
margin-bottom: 20px;
}
label {
font-size: 14pt;
}
.left {
float: left;
}
.right {
float: right;
}
.inputWrp {
position: relative;
}
.inputWrp .inputText {
height: 35px;
width: 90%;
margin-bottom: 20px;
border: 1px solid #ccc;
border-top: none;
border-right: none;
}
.inputWrp .floating_label {
position: absolute;
pointer-events: none;
top: 20px;
left: 10px;
transition: 0.2s ease all;
}
.inputWrp input:focus ~ .floating_label,
.inputWrp input:not(:focus):valid ~ .floating_label {
top: 0px;
left: 20px;
font-size: 10px;
color: blue;
opacity: 1;
}

340
tools/esp8266/main.cpp

@ -0,0 +1,340 @@
#include "main.h"
#include "version.h"
#include "html/h/style_css.h"
#include "html/h/setup_html.h"
Main::Main(void) {
mDns = new DNSServer();
mWeb = new ESP8266WebServer(80);
mUpdater = new ESP8266HTTPUpdateServer();
mUdp = new WiFiUDP();
mApActive = true;
snprintf(mVersion, 12, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
memset(&mDeviceName, 0, DEVNAME_LEN);
mEep = new eep();
Serial.begin(115200);
mUptimeSecs = 0;
mUptimeTicker = new Ticker();
mUptimeTicker->attach(1, std::bind(&Main::uptimeTicker, this));
}
//-----------------------------------------------------------------------------
void Main::setup(const char *ssid, const char *pwd, uint32_t timeout) {
bool startAp = mApActive;
mWeb->on("/setup", std::bind(&Main::showSetup, this));
mWeb->on("/save", std::bind(&Main::showSave, this));
mWeb->on("/uptime", std::bind(&Main::showUptime, this));
mWeb->on("/time", std::bind(&Main::showTime, this));
mWeb->on("/style.css", std::bind(&Main::showCss, this));
mWeb->on("/reboot", std::bind(&Main::showReboot, this));
mWeb->onNotFound (std::bind(&Main::showNotFound, this));
startAp = getConfig();
if(String(mDeviceName) != "")
WiFi.hostname(mDeviceName);
if(false == startAp)
startAp = setupStation(timeout);
if(true == startAp) {
if(strlen(pwd) < 8)
Serial.println("password must be at least 8 characters long");
setupAp(ssid, pwd);
}
mUpdater->setup(mWeb);
mApActive = startAp;
mTimestamp = getNtpTime();
//Serial.println("[NTP]: " + getDateTimeStr(getNtpTime()));
}
//-----------------------------------------------------------------------------
void Main::loop(void) {
if(mApActive)
mDns->processNextRequest();
mWeb->handleClient();
}
//-----------------------------------------------------------------------------
bool Main::getConfig(void) {
bool mApActive = false;
mEep->read(ADDR_SSID, mStationSsid, SSID_LEN);
mEep->read(ADDR_PWD, mStationPwd, PWD_LEN);
mEep->read(ADDR_DEVNAME, mDeviceName, DEVNAME_LEN);
if(mStationSsid[0] == 0xff) { // empty memory
mApActive = true;
memset(mStationSsid, 0, SSID_LEN);
}
if(mStationPwd[0] == 0xff)
memset(mStationPwd, 0, PWD_LEN);
if(mDeviceName[0] == 0xff)
memset(mDeviceName, 0, DEVNAME_LEN);
return mApActive;
}
//-----------------------------------------------------------------------------
void Main::setupAp(const char *ssid, const char *pwd) {
IPAddress apIp(192, 168, 1, 1);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIp, apIp, IPAddress(255, 255, 255, 0));
WiFi.softAP(ssid, pwd);
mDns->start(mDnsPort, "*", apIp);
mWeb->onNotFound([&]() {
showSetup();
});
mWeb->on("/", std::bind(&Main::showSetup, this));
mWeb->begin();
}
//-----------------------------------------------------------------------------
bool Main::setupStation(uint32_t timeout) {
int32_t cnt = timeout * 10;
bool startAp = false;
WiFi.mode(WIFI_STA);
WiFi.begin(mStationSsid, mStationPwd);
delay(5000);
Serial.println("wait for network");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
if(cnt % 100 == 0)
Serial.println(".");
else
Serial.print(".");
if(timeout > 0) { // limit == 0 -> no limit
if(--cnt <= 0) {
startAp = true;
WiFi.disconnect();
delay(100);
break;
}
}
}
Serial.println(".");
if(false == startAp) {
mWeb->begin();
}
delay(1000);
return startAp;
}
//-----------------------------------------------------------------------------
void Main::showSetup(void) {
String html = setup_html;
html.replace("{SSID}", mStationSsid);
// PWD will be left at the default value (for protection)
// -> the PWD will only be changed if it does not match the default "{PWD}"
html.replace("{DEVICE}", String(mDeviceName));
html.replace("{VERSION}", String(mVersion));
mWeb->send(200, "text/html", html);
}
//-----------------------------------------------------------------------------
void Main::showCss(void) {
mWeb->send(200, "text/css", style_css);
}
//-----------------------------------------------------------------------------
void Main::showSave(void) {
saveValues(true);
}
//-----------------------------------------------------------------------------
void Main::saveValues(bool webSend = true) {
if(mWeb->args() > 0) {
if(mWeb->arg("ssid") != "") {
memset(mStationSsid, 0, SSID_LEN);
mWeb->arg("ssid").toCharArray(mStationSsid, SSID_LEN);
mEep->write(ADDR_SSID, mStationSsid, SSID_LEN);
if(mWeb->arg("pwd") != "{PWD}") {
memset(mStationPwd, 0, PWD_LEN);
mWeb->arg("pwd").toCharArray(mStationPwd, PWD_LEN);
mEep->write(ADDR_PWD, mStationPwd, PWD_LEN);
}
}
memset(mDeviceName, 0, DEVNAME_LEN);
mWeb->arg("device").toCharArray(mDeviceName, DEVNAME_LEN);
mEep->write(ADDR_DEVNAME, mDeviceName, DEVNAME_LEN);
if(webSend) {
if(mWeb->arg("reboot") == "on")
showReboot();
else
mWeb->send(200, "text/html", "<!doctype html><html><head><title>Setup saved</title><meta http-equiv=\"refresh\" content=\"0; URL=/setup\"></head><body>"
"<p>saved</p></body></html>");
}
}
}
//-----------------------------------------------------------------------------
void Main::showUptime(void) {
char time[20] = {0};
int upTimeSc = uint32_t((mUptimeSecs) % 60);
int upTimeMn = uint32_t((mUptimeSecs / (60)) % 60);
int upTimeHr = uint32_t((mUptimeSecs / (60 * 60)) % 24);
int upTimeDy = uint32_t((mUptimeSecs / (60 * 60 * 24)) % 365);
snprintf(time, 20, "%d Tage, %02d:%02d:%02d", upTimeDy, upTimeHr, upTimeMn, upTimeSc);
mWeb->send(200, "text/plain", String(time));
}
//-----------------------------------------------------------------------------
void Main::showTime(void) {
mWeb->send(200, "text/plain", getDateTimeStr(mTimestamp));
}
//-----------------------------------------------------------------------------
void Main::showNotFound(void) {
String msg = "File Not Found\n\n";
msg += "URI: ";
msg += mWeb->uri();
msg += "\nMethod: ";
msg += ( mWeb->method() == HTTP_GET ) ? "GET" : "POST";
msg += "\nArguments: ";
msg += mWeb->args();
msg += "\n";
for(uint8_t i = 0; i < mWeb->args(); i++ ) {
msg += " " + mWeb->argName(i) + ": " + mWeb->arg(i) + "\n";
}
mWeb->send(404, "text/plain", msg);
}
//-----------------------------------------------------------------------------
void Main::showReboot(void) {
mWeb->send(200, "text/html", "<!doctype html><html><head><title>Rebooting ...</title><meta http-equiv=\"refresh\" content=\"10; URL=/\"></head><body>rebooting ... auto reload after 10s</body></html>");
delay(1000);
ESP.restart();
}
//-----------------------------------------------------------------------------
void Main::uptimeTicker(void) {
mUptimeSecs++;
mTimestamp++;
}
//-----------------------------------------------------------------------------
time_t Main::getNtpTime(void) {
time_t date = 0;
IPAddress timeServer;
uint8_t buf[NTP_PACKET_SIZE];
uint8_t retry = 0;
WiFi.hostByName (TIMESERVER_NAME, timeServer);
mUdp->begin(TIME_LOCAL_PORT);
sendNTPpacket(timeServer);
while(retry++ < 5) {
int wait = 150;
while(--wait) {
if(NTP_PACKET_SIZE <= mUdp->parsePacket()) {
uint64_t secsSince1900;
mUdp->read(buf, NTP_PACKET_SIZE);
secsSince1900 = (buf[40] << 24);
secsSince1900 |= (buf[41] << 16);
secsSince1900 |= (buf[42] << 8);
secsSince1900 |= (buf[43] );
date = secsSince1900 - 2208988800UL; // UTC time
date += (TIMEZONE + offsetDayLightSaving(date)) * 3600;
break;
}
else
delay(10);
}
}
return date;
}
//-----------------------------------------------------------------------------
void Main::sendNTPpacket(IPAddress& address) {
uint8_t buf[NTP_PACKET_SIZE] = {0};
buf[0] = B11100011; // LI, Version, Mode
buf[1] = 0; // Stratum
buf[2] = 6; // Max Interval between messages in seconds
buf[3] = 0xEC; // Clock Precision
// bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset
buf[12] = 49; // four-byte reference ID identifying
buf[13] = 0x4E;
buf[14] = 49;
buf[15] = 52;
mUdp->beginPacket(address, 123); // NTP request, port 123
mUdp->write(buf, NTP_PACKET_SIZE);
mUdp->endPacket();
}
//-----------------------------------------------------------------------------
String Main::getDateTimeStr(time_t t) {
char str[20] = {0};
sprintf(str, "%04d-%02d-%02d+%02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t));
return String(str);
}
//-----------------------------------------------------------------------------
// calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
// from: https://forum.arduino.cc/index.php?topic=172044.msg1278536#msg1278536
time_t Main::offsetDayLightSaving (uint32_t local_t) {
int m = month (local_t);
if(m < 3 || m > 10) return 0; // no DSL in Jan, Feb, Nov, Dez
if(m > 3 && m < 10) return 1; // DSL in Apr, May, Jun, Jul, Aug, Sep
int y = year (local_t);
int h = hour (local_t);
int hToday = (h + 24 * day(local_t));
if((m == 3 && hToday >= (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 4) % 7)))
|| (m == 10 && hToday < (1 + TIMEZONE + 24 * (31 - (5 * y /4 + 1) % 7))) )
return 1;
else
return 0;
}

79
tools/esp8266/main.h

@ -0,0 +1,79 @@
#ifndef __MAIN_H__
#define __MAIN_H__
#include "Arduino.h"
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <Ticker.h>
#include <ESP8266HTTPUpdateServer.h>
// NTP
#include <WiFiUdp.h>
#include <TimeLib.h>
#include "eep.h"
#include "defines.h"
const byte mDnsPort = 53;
/* TIMESERVER CONFIG */
#define TIMESERVER_NAME "pool.ntp.org"
#define TIME_LOCAL_PORT 8888
#define NTP_PACKET_SIZE 48
#define TIMEZONE 1 // Central European time +1
class Main {
public:
Main(void);
virtual void setup(const char *ssid, const char *pwd, uint32_t timeout);
virtual void loop();
String getDateTimeStr (time_t t);
protected:
void showReboot(void);
virtual void saveValues(bool webSend);
char mStationSsid[SSID_LEN];
char mStationPwd[PWD_LEN];
bool mLinkLedActive;
bool mApActive;
ESP8266WebServer *mWeb;
char mVersion[9];
char mDeviceName[DEVNAME_LEN];
eep *mEep;
uint32_t mTimestamp;
private:
bool getConfig(void);
void setupAp(const char *ssid, const char *pwd);
bool setupStation(uint32_t timeout);
void showNotFound(void);
virtual void showSetup(void);
virtual void showSave(void);
void showUptime(void);
void showTime(void);
void showCss(void);
void uptimeTicker(void);
time_t getNtpTime(void);
void sendNTPpacket(IPAddress& address);
time_t offsetDayLightSaving (uint32_t local_t);
Ticker *mUptimeTicker;
uint32_t mUptimeSecs;
DNSServer *mDns;
ESP8266HTTPUpdateServer *mUpdater;
WiFiUDP *mUdp; // for time server
};
#endif /*__MAIN_H__*/

BIN
tools/esp8266/tools/fileConv.exe

Binary file not shown.
Loading…
Cancel
Save