Merge remote-tracking branch 'tbnobody/OpenDTU/master'
This commit is contained in:
commit
df5cde2e82
11
README.md
11
README.md
@ -172,7 +172,7 @@ This can be achieved by editing the 'platformio.ini' file and add/change one or
|
|||||||
* erase flash: `platformio run -e generic -t erase`
|
* erase flash: `platformio run -e generic -t erase`
|
||||||
|
|
||||||
### using the pre-compiled .bin files
|
### using the pre-compiled .bin files
|
||||||
The pre-compiled files can be found on the [github page](https://github.com/tbnobody/OpenDTU) in the tab "Actions" and the sub menu "OpenDTU Build". Just choose the latest build from the master branch (blue font). You need to be logged in with your github account to download the files.
|
The pre-compiled files can be found on the [github page](https://github.com/tbnobody/OpenDTU) in the tab "Actions" and the sub menu "OpenDTU Build". Just choose the latest build from the master branch (search for "master" in the blue font text but click on the white header text!). You need to be logged in with your github account to download the files.
|
||||||
Use a ESP32 flash tool of your choice (see next chapter) and flash the `.bin` files to the right addresses:
|
Use a ESP32 flash tool of your choice (see next chapter) and flash the `.bin` files to the right addresses:
|
||||||
|
|
||||||
| Address | File |
|
| Address | File |
|
||||||
@ -184,7 +184,7 @@ Use a ESP32 flash tool of your choice (see next chapter) and flash the `.bin` fi
|
|||||||
|
|
||||||
For further updates you can just use the web interface and upload the `opendtu-*.bin` file.
|
For further updates you can just use the web interface and upload the `opendtu-*.bin` file.
|
||||||
|
|
||||||
### Flash with esptool.py (Linux)
|
#### Flash with esptool.py (Linux)
|
||||||
```
|
```
|
||||||
esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_reset \
|
esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_reset \
|
||||||
write_flash --flash_mode dout --flash_freq 40m --flash_size detect \
|
write_flash --flash_mode dout --flash_freq 40m --flash_size detect \
|
||||||
@ -194,7 +194,7 @@ esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_
|
|||||||
0x10000 opendtu-generic.bin
|
0x10000 opendtu-generic.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
### Flash with Espressif Flash Download Tool (Windows)
|
#### Flash with Espressif Flash Download Tool (Windows)
|
||||||
|
|
||||||
[Download link](https://www.espressif.com/en/support/download/other-tools)
|
[Download link](https://www.espressif.com/en/support/download/other-tools)
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_
|
|||||||
- To program, press "Start" on screen, then the "Boot" button.
|
- To program, press "Start" on screen, then the "Boot" button.
|
||||||
- When flashing is complete (FINISH appears) then press the Reset button on the ESP32 board (or powercycle ) to start the OpenDTU application.
|
- When flashing is complete (FINISH appears) then press the Reset button on the ESP32 board (or powercycle ) to start the OpenDTU application.
|
||||||
|
|
||||||
### Flash with ESP_Flasher (Windows)
|
#### Flash with ESP_Flasher (Windows)
|
||||||
Users report that [ESP_Flasher](https://github.com/Jason2866/ESP_Flasher/releases/) is suitable for flashing OpenDTU on Windows.
|
Users report that [ESP_Flasher](https://github.com/Jason2866/ESP_Flasher/releases/) is suitable for flashing OpenDTU on Windows.
|
||||||
|
|
||||||
## First configuration
|
## First configuration
|
||||||
@ -236,6 +236,9 @@ A documentation of the Web API can be found here: [Web-API Documentation](docs/W
|
|||||||
## Available cases
|
## Available cases
|
||||||
* <https://www.thingiverse.com/thing:5435911>
|
* <https://www.thingiverse.com/thing:5435911>
|
||||||
* <https://www.printables.com/model/293003-sol-opendtu-esp32-nrf24l01-case>
|
* <https://www.printables.com/model/293003-sol-opendtu-esp32-nrf24l01-case>
|
||||||
|
* <https://www.thingiverse.com/thing:5661780>
|
||||||
|
* <https://www.thingiverse.com/thing:5632374>
|
||||||
|
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
* Building the WebApp
|
* Building the WebApp
|
||||||
|
|||||||
@ -66,8 +66,8 @@ cmd topics are used to set values. Status topics are updated from values set in
|
|||||||
| [serial]/status/limit_relative | R | Current applied production limit of the inverter | % of total possible output |
|
| [serial]/status/limit_relative | R | Current applied production limit of the inverter | % of total possible output |
|
||||||
| [serial]/status/limit_absolute | R | Current applied production limit of the inverter | Watt (W) |
|
| [serial]/status/limit_absolute | R | Current applied production limit of the inverter | Watt (W) |
|
||||||
| [serial]/cmd/limit_persistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
| [serial]/cmd/limit_persistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
||||||
| [serial]/cmd/limit_persistent_absolute | W | Set the inverter limit as a absolute value. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic after around 4 minutes. | Watt (W) |
|
| [serial]/cmd/limit_persistent_absolute | W | Set the inverter limit as a absolute value. The value will survive the night without power. The updated value will set immediatly within the inverter but show up in the web GUI and limit_relative topic after around 4 minutes. If you are using a already known inverter (known Hardware ID), the updated value will show up within a few seconds. | Watt (W) |
|
||||||
| [serial]/cmd/limit_nonpersistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will reset to the last persistent value at night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
| [serial]/cmd/limit_nonpersistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will reset to the last persistent value at night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
||||||
| [serial]/cmd/limit_nonpersistent_absolute | W | Set the inverter limit as a absolute value. The value will reset to the last persistent value at night without power. The updated value will show up in the web GUI and limit_relative topic after around 4 minutes. | Watt (W) |
|
| [serial]/cmd/limit_nonpersistent_absolute | W | Set the inverter limit as a absolute value. The value will reset to the last persistent value at night without power. The updated value will set immediatly within the inverter but show up in the web GUI and limit_relative topic after around 4 minutes. If you are using a already known inverter (known Hardware ID), the updated value will show up within a few seconds. | Watt (W) |
|
||||||
| [serial]/cmd/power | W | Turn the inverter on (1) or off (0) | 0 or 1 |
|
| [serial]/cmd/power | W | Turn the inverter on (1) or off (0) | 0 or 1 |
|
||||||
| [serial]/cmd/restart | W | Restarts the inverters (also resets YieldDay) | 1 |
|
| [serial]/cmd/restart | W | Restarts the inverters (also resets YieldDay) | 1 |
|
||||||
|
|||||||
@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#ifdef ESP8266
|
|
||||||
#define DISABLE_IRQ noInterrupts()
|
|
||||||
#define RESTORE_IRQ interrupts()
|
|
||||||
#elif ESP32
|
|
||||||
#define DISABLE_IRQ ;
|
|
||||||
#define RESTORE_IRQ ;
|
|
||||||
#else
|
|
||||||
#define DISABLE_IRQ \
|
|
||||||
uint8_t sreg = SREG; \
|
|
||||||
cli();
|
|
||||||
|
|
||||||
#define RESTORE_IRQ \
|
|
||||||
SREG = sreg;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class BUFFERTYPE, uint8_t BUFFERSIZE>
|
|
||||||
class CircularBuffer {
|
|
||||||
|
|
||||||
typedef BUFFERTYPE BufferType;
|
|
||||||
BufferType Buffer[BUFFERSIZE];
|
|
||||||
|
|
||||||
public:
|
|
||||||
CircularBuffer() : m_buff(Buffer) {
|
|
||||||
m_size = BUFFERSIZE;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t getFill(void) const {
|
|
||||||
return m_fill;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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.
|
|
||||||
*/
|
|
||||||
BUFFERTYPE* getFront(void) const
|
|
||||||
{
|
|
||||||
DISABLE_IRQ;
|
|
||||||
BUFFERTYPE* 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(BUFFERTYPE* record)
|
|
||||||
{
|
|
||||||
bool ok = false;
|
|
||||||
DISABLE_IRQ;
|
|
||||||
if (!full())
|
|
||||||
{
|
|
||||||
BUFFERTYPE* 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.
|
|
||||||
*/
|
|
||||||
BUFFERTYPE* getBack(void) const
|
|
||||||
{
|
|
||||||
BUFFERTYPE* 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 BUFFERTYPE * 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t m_size; // Total number of records that can be stored in the buffer.
|
|
||||||
BUFFERTYPE* const m_buff;
|
|
||||||
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
|
|
||||||
@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
HoymilesClass Hoymiles;
|
HoymilesClass Hoymiles;
|
||||||
|
|
||||||
void HoymilesClass::init()
|
void HoymilesClass::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||||
{
|
{
|
||||||
_xSemaphore = xSemaphoreCreateMutex();
|
_xSemaphore = xSemaphoreCreateMutex();
|
||||||
HOY_SEMAPHORE_GIVE(); // release before first use
|
HOY_SEMAPHORE_GIVE(); // release before first use
|
||||||
|
|
||||||
_pollInterval = 0;
|
_pollInterval = 0;
|
||||||
_radio.reset(new HoymilesRadio());
|
_radio.reset(new HoymilesRadio());
|
||||||
_radio->init();
|
_radio->init(initialisedSpiBus, pinCE, pinIRQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HoymilesClass::loop()
|
void HoymilesClass::loop()
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
class HoymilesClass {
|
class HoymilesClass {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
std::shared_ptr<InverterAbstract> addInverter(const char* name, uint64_t serial);
|
std::shared_ptr<InverterAbstract> addInverter(const char* name, uint64_t serial);
|
||||||
|
|||||||
@ -5,15 +5,14 @@
|
|||||||
#include <Every.h>
|
#include <Every.h>
|
||||||
#include <FunctionalInterrupt.h>
|
#include <FunctionalInterrupt.h>
|
||||||
|
|
||||||
void HoymilesRadio::init()
|
void HoymilesRadio::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ)
|
||||||
{
|
{
|
||||||
_dtuSerial.u64 = 0;
|
_dtuSerial.u64 = 0;
|
||||||
|
|
||||||
_hspi.reset(new SPIClass(HSPI));
|
_spiPtr.reset(initialisedSpiBus);
|
||||||
_radio.reset(new RF24(HOYMILES_PIN_CE, HOYMILES_PIN_CS));
|
_radio.reset(new RF24(pinCE, initialisedSpiBus->pinSS()));
|
||||||
|
|
||||||
_hspi->begin(HOYMILES_PIN_SCLK, HOYMILES_PIN_MISO, HOYMILES_PIN_MOSI, HOYMILES_PIN_CS);
|
_radio->begin(_spiPtr.get());
|
||||||
_radio->begin(_hspi.get());
|
|
||||||
|
|
||||||
_radio->setDataRate(RF24_250KBPS);
|
_radio->setDataRate(RF24_250KBPS);
|
||||||
_radio->enableDynamicPayloads();
|
_radio->enableDynamicPayloads();
|
||||||
@ -27,7 +26,7 @@ void HoymilesRadio::init()
|
|||||||
Serial.println(F("Connection error!!"));
|
Serial.println(F("Connection error!!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
attachInterrupt(digitalPinToInterrupt(HOYMILES_PIN_IRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
|
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
|
||||||
|
|
||||||
openReadingPipe();
|
openReadingPipe();
|
||||||
_radio->startListening();
|
_radio->startListening();
|
||||||
@ -43,17 +42,15 @@ void HoymilesRadio::loop()
|
|||||||
if (_packetReceived) {
|
if (_packetReceived) {
|
||||||
Serial.println(F("Interrupt received"));
|
Serial.println(F("Interrupt received"));
|
||||||
while (_radio->available()) {
|
while (_radio->available()) {
|
||||||
if (!_rxBuffer.full()) {
|
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
|
||||||
fragment_t* f;
|
fragment_t f;
|
||||||
f = _rxBuffer.getFront();
|
memset(f.fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
||||||
memset(f->fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
f.len = _radio->getDynamicPayloadSize();
|
||||||
f->len = _radio->getDynamicPayloadSize();
|
f.channel = _radio->getChannel();
|
||||||
f->channel = _radio->getChannel();
|
if (f.len > MAX_RF_PAYLOAD_SIZE)
|
||||||
if (f->len > MAX_RF_PAYLOAD_SIZE)
|
f.len = MAX_RF_PAYLOAD_SIZE;
|
||||||
f->len = MAX_RF_PAYLOAD_SIZE;
|
_radio->read(f.fragment, f.len);
|
||||||
|
_rxBuffer.push(f);
|
||||||
_radio->read(f->fragment, f->len);
|
|
||||||
_rxBuffer.pushFront(f);
|
|
||||||
} else {
|
} else {
|
||||||
Serial.println(F("Buffer full"));
|
Serial.println(F("Buffer full"));
|
||||||
_radio->flush_rx();
|
_radio->flush_rx();
|
||||||
@ -64,16 +61,16 @@ void HoymilesRadio::loop()
|
|||||||
} else {
|
} else {
|
||||||
// Perform package parsing only if no packages are received
|
// Perform package parsing only if no packages are received
|
||||||
if (!_rxBuffer.empty()) {
|
if (!_rxBuffer.empty()) {
|
||||||
fragment_t* f = _rxBuffer.getBack();
|
fragment_t f = _rxBuffer.back();
|
||||||
if (checkFragmentCrc(f)) {
|
if (checkFragmentCrc(&f)) {
|
||||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(f);
|
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||||
|
|
||||||
if (nullptr != inv) {
|
if (nullptr != inv) {
|
||||||
// Save packet in inverter rx buffer
|
// Save packet in inverter rx buffer
|
||||||
char buf[30];
|
char buf[30];
|
||||||
snprintf(buf, sizeof(buf), "RX Channel: %d --> ", f->channel);
|
snprintf(buf, sizeof(buf), "RX Channel: %d --> ", f.channel);
|
||||||
dumpBuf(buf, f->fragment, f->len);
|
dumpBuf(buf, f.fragment, f.len);
|
||||||
inv->addRxFragment(f->fragment, f->len);
|
inv->addRxFragment(f.fragment, f.len);
|
||||||
} else {
|
} else {
|
||||||
Serial.println(F("Inverter Not found!"));
|
Serial.println(F("Inverter Not found!"));
|
||||||
}
|
}
|
||||||
@ -83,7 +80,7 @@ void HoymilesRadio::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove paket from buffer even it was corrupted
|
// Remove paket from buffer even it was corrupted
|
||||||
_rxBuffer.popBack();
|
_rxBuffer.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CircularBuffer.h"
|
|
||||||
#include "TimeoutHelper.h"
|
#include "TimeoutHelper.h"
|
||||||
#include "commands/CommandAbstract.h"
|
#include "commands/CommandAbstract.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -12,33 +11,9 @@
|
|||||||
// number of fragments hold in buffer
|
// number of fragments hold in buffer
|
||||||
#define FRAGMENT_BUFFER_SIZE 30
|
#define FRAGMENT_BUFFER_SIZE 30
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_MISO
|
|
||||||
#define HOYMILES_PIN_MISO 19
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_MOSI
|
|
||||||
#define HOYMILES_PIN_MOSI 23
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_SCLK
|
|
||||||
#define HOYMILES_PIN_SCLK 18
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_IRQ
|
|
||||||
#define HOYMILES_PIN_IRQ 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_CE
|
|
||||||
#define HOYMILES_PIN_CE 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HOYMILES_PIN_CS
|
|
||||||
#define HOYMILES_PIN_CS 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class HoymilesRadio {
|
class HoymilesRadio {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pinIRQ);
|
||||||
void loop();
|
void loop();
|
||||||
void setPALevel(rf24_pa_dbm_e paLevel);
|
void setPALevel(rf24_pa_dbm_e paLevel);
|
||||||
|
|
||||||
@ -71,7 +46,7 @@ private:
|
|||||||
void sendRetransmitPacket(uint8_t fragment_id);
|
void sendRetransmitPacket(uint8_t fragment_id);
|
||||||
void sendLastPacketAgain();
|
void sendLastPacketAgain();
|
||||||
|
|
||||||
std::unique_ptr<SPIClass> _hspi;
|
std::unique_ptr<SPIClass> _spiPtr;
|
||||||
std::unique_ptr<RF24> _radio;
|
std::unique_ptr<RF24> _radio;
|
||||||
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
||||||
uint8_t _rxChIdx = 0;
|
uint8_t _rxChIdx = 0;
|
||||||
@ -81,7 +56,7 @@ private:
|
|||||||
|
|
||||||
volatile bool _packetReceived = false;
|
volatile bool _packetReceived = false;
|
||||||
|
|
||||||
CircularBuffer<fragment_t, FRAGMENT_BUFFER_SIZE> _rxBuffer;
|
std::queue<fragment_t> _rxBuffer;
|
||||||
TimeoutHelper _rxTimeout;
|
TimeoutHelper _rxTimeout;
|
||||||
|
|
||||||
serial_u _dtuSerial;
|
serial_u _dtuSerial;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ const devInfo_t devInfo[] = {
|
|||||||
{ { 0x10, 0x11, 0x30, ALL }, 800, "HM-800" },
|
{ { 0x10, 0x11, 0x30, ALL }, 800, "HM-800" },
|
||||||
{ { 0x10, 0x11, 0x40, ALL }, 800, "HM-800" },
|
{ { 0x10, 0x11, 0x40, ALL }, 800, "HM-800" },
|
||||||
{ { 0x10, 0x12, 0x10, ALL }, 1200, "HM-1200" },
|
{ { 0x10, 0x12, 0x10, ALL }, 1200, "HM-1200" },
|
||||||
|
{ { 0x10, 0x02, 0x30, ALL }, 1500, "MI-1500 Gen3" },
|
||||||
{ { 0x10, 0x12, 0x30, ALL }, 1500, "HM-1500" },
|
{ { 0x10, 0x12, 0x30, ALL }, 1500, "HM-1500" },
|
||||||
{ { 0x10, 0x10, 0x10, 0x15 }, static_cast<uint16_t>(300 * 0.7), "HM-300" }, // HM-300 factory limitted to 70%
|
{ { 0x10, 0x10, 0x10, 0x15 }, static_cast<uint16_t>(300 * 0.7), "HM-300" }, // HM-300 factory limitted to 70%
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,12 +36,19 @@ monitor_speed = 115200
|
|||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
|
|
||||||
; Specify port here. Comment out (add ; in front of line) to use auto detection.
|
; Specify port here. Comment out (add ; in front of line) to use auto detection.
|
||||||
monitor_port = COM5
|
monitor_port = COM4
|
||||||
upload_port = COM5
|
upload_port = COM4
|
||||||
|
|
||||||
|
|
||||||
[env:generic]
|
[env:generic]
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
|
build_flags = ${env.build_flags}
|
||||||
|
-DHOYMILES_PIN_MISO=19
|
||||||
|
-DHOYMILES_PIN_MOSI=23
|
||||||
|
-DHOYMILES_PIN_SCLK=18
|
||||||
|
-DHOYMILES_PIN_IRQ=16
|
||||||
|
-DHOYMILES_PIN_CE=4
|
||||||
|
-DHOYMILES_PIN_CS=5
|
||||||
|
|
||||||
|
|
||||||
[env:olimex_esp32_poe]
|
[env:olimex_esp32_poe]
|
||||||
@ -97,6 +104,7 @@ build_flags = ${env.build_flags}
|
|||||||
-DHOYMILES_PIN_CS=15
|
-DHOYMILES_PIN_CS=15
|
||||||
-DOPENDTU_ETHERNET
|
-DOPENDTU_ETHERNET
|
||||||
|
|
||||||
|
|
||||||
[env:LilyGO_T_ETH_POE]
|
[env:LilyGO_T_ETH_POE]
|
||||||
; http://www.lilygo.cn/claprod_view.aspx?TypeId=21&Id=1344&FId=t28:21:28
|
; http://www.lilygo.cn/claprod_view.aspx?TypeId=21&Id=1344&FId=t28:21:28
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
@ -114,3 +122,28 @@ build_flags = ${env.build_flags}
|
|||||||
-DETH_ADDR=0
|
-DETH_ADDR=0
|
||||||
-DETH_MDC_PIN=23
|
-DETH_MDC_PIN=23
|
||||||
-DETH_MDIO_PIN=18
|
-DETH_MDIO_PIN=18
|
||||||
|
|
||||||
|
|
||||||
|
[env:esp_s3_12k_kit]
|
||||||
|
; https://www.waveshare.com/wiki/NodeMCU-ESP-S3-12K-Kit
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
build_flags = ${env.build_flags}
|
||||||
|
-DHOYMILES_PIN_MISO=16
|
||||||
|
-DHOYMILES_PIN_MOSI=17
|
||||||
|
-DHOYMILES_PIN_SCLK=18
|
||||||
|
-DHOYMILES_PIN_IRQ=3
|
||||||
|
-DHOYMILES_PIN_CE=4
|
||||||
|
-DHOYMILES_PIN_CS=5
|
||||||
|
|
||||||
|
|
||||||
|
[env:lolin32_lite]
|
||||||
|
; https://www.makershop.de/plattformen/esp8266/wemos-lolin32/
|
||||||
|
; https://www.az-delivery.de/products/esp32-lolin-lolin32
|
||||||
|
board = lolin32_lite
|
||||||
|
build_flags = ${env.build_flags}
|
||||||
|
-DHOYMILES_PIN_MISO=19
|
||||||
|
-DHOYMILES_PIN_MOSI=23
|
||||||
|
-DHOYMILES_PIN_SCLK=18
|
||||||
|
-DHOYMILES_PIN_IRQ=16
|
||||||
|
-DHOYMILES_PIN_CE=17
|
||||||
|
-DHOYMILES_PIN_CS=5
|
||||||
@ -120,7 +120,7 @@ void MqttHassPublishingClass::publishField(std::shared_ptr<InverterAbstract> inv
|
|||||||
createDeviceInfo(deviceObj, inv);
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
if (Configuration.get().Mqtt_Hass_Expire) {
|
if (Configuration.get().Mqtt_Hass_Expire) {
|
||||||
root[F("exp_aft")] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 2;
|
root[F("exp_aft")] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 3;
|
||||||
}
|
}
|
||||||
if (devCls != 0) {
|
if (devCls != 0) {
|
||||||
root[F("dev_cla")] = devCls;
|
root[F("dev_cla")] = devCls;
|
||||||
|
|||||||
@ -277,6 +277,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
|
|||||||
local.tm_mday = root[F("day")].as<uint>(); // day of the month - [ 1 to 31 ]
|
local.tm_mday = root[F("day")].as<uint>(); // day of the month - [ 1 to 31 ]
|
||||||
local.tm_mon = root[F("month")].as<uint>() - 1; // months since January - [ 0 to 11 ]
|
local.tm_mon = root[F("month")].as<uint>() - 1; // months since January - [ 0 to 11 ]
|
||||||
local.tm_year = root[F("year")].as<uint>() - 1900; // years since 1900
|
local.tm_year = root[F("year")].as<uint>() - 1900; // years since 1900
|
||||||
|
local.tm_isdst = -1;
|
||||||
|
|
||||||
time_t t = mktime(&local);
|
time_t t = mktime(&local);
|
||||||
struct timeval now = { .tv_sec = t, .tv_usec = 0 };
|
struct timeval now = { .tv_sec = t, .tv_usec = 0 };
|
||||||
|
|||||||
@ -96,7 +96,9 @@ void setup()
|
|||||||
|
|
||||||
// Initialize inverter communication
|
// Initialize inverter communication
|
||||||
Serial.print(F("Initialize Hoymiles interface... "));
|
Serial.print(F("Initialize Hoymiles interface... "));
|
||||||
Hoymiles.init();
|
SPIClass* spiClass = new SPIClass(HSPI);
|
||||||
|
spiClass->begin(HOYMILES_PIN_SCLK, HOYMILES_PIN_MISO, HOYMILES_PIN_MOSI, HOYMILES_PIN_CS);
|
||||||
|
Hoymiles.init(spiClass, HOYMILES_PIN_CE, HOYMILES_PIN_IRQ);
|
||||||
|
|
||||||
Serial.println(F(" Setting radio PA level... "));
|
Serial.println(F(" Setting radio PA level... "));
|
||||||
Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
"@vue/eslint-config-typescript": "^11.0.2",
|
"@vue/eslint-config-typescript": "^11.0.2",
|
||||||
"@vue/tsconfig": "^0.1.3",
|
"@vue/tsconfig": "^0.1.3",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-plugin-vue": "^9.7.0",
|
"eslint-plugin-vue": "^9.8.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.56.1",
|
||||||
"typescript": "^4.9.3",
|
"typescript": "^4.9.3",
|
||||||
|
|||||||
@ -99,13 +99,13 @@
|
|||||||
<input type="number" class="form-control" :id="`inverter-max_${index}`" min="0"
|
<input type="number" class="form-control" :id="`inverter-max_${index}`" min="0"
|
||||||
v-model="selectedInverterData.channel[index].max_power"
|
v-model="selectedInverterData.channel[index].max_power"
|
||||||
:aria-describedby="`inverter-maxDescription_${index} inverter-customizer`" />
|
:aria-describedby="`inverter-maxDescription_${index} inverter-customizer`" />
|
||||||
<span class="input-group-text" :id="`inverter-maxDescription_${index}`">W<sup>*</sup></span>
|
<span class="input-group-text" :id="`inverter-maxDescription_${index}`">W<sub>p</sub><sup>*</sup></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :id="`inverter-customizer`" class="form-text">*) Input the kWp of the channel to
|
<div :id="`inverter-customizer`" class="form-text">*) Input the W<sub>p</sub> of the channel to
|
||||||
calculate irradiation.</div>
|
calculate irradiation.</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,8 @@
|
|||||||
<div class="alert alert-secondary" role="alert">
|
<div class="alert alert-secondary" role="alert">
|
||||||
<b>Hint:</b> You can use the manual time synchronization to set the current time of OpenDTU if
|
<b>Hint:</b> You can use the manual time synchronization to set the current time of OpenDTU if
|
||||||
no NTP server is available. But be aware, that in case of power cycle the time gets lost. Also
|
no NTP server is available. But be aware, that in case of power cycle the time gets lost. Also
|
||||||
the time accurancy can be very bad as it is not resynchronised regularly.
|
note that time accuracy will be skewed badly, as it can not be resynchronised regularly and the
|
||||||
|
ESP32 microcontroller does not have a real time clock.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -878,10 +878,10 @@ escape-string-regexp@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||||
|
|
||||||
eslint-plugin-vue@^9.7.0:
|
eslint-plugin-vue@^9.8.0:
|
||||||
version "9.7.0"
|
version "9.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.7.0.tgz#d391b9864f128ea2d1ee4dabeafb5f7c0cea981f"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.8.0.tgz#91de2aabbee8cdbef078ccd4f650a9ecfa445f4f"
|
||||||
integrity sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==
|
integrity sha512-E/AXwcTzunyzM83C2QqDHxepMzvI2y6x+mmeYHbVDQlKFqmKYvRrhaVixEeeG27uI44p9oKDFiyCRw4XxgtfHA==
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-utils "^3.0.0"
|
eslint-utils "^3.0.0"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user