Merge branch 'master' of https://github.com/tbnobody/OpenDTU into Database
This commit is contained in:
commit
db3b5a62a3
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -18,14 +18,14 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
@ -56,7 +56,7 @@ jobs:
|
||||
run: git fetch --force --tags origin
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
@ -64,13 +64,13 @@ jobs:
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
|
||||
2
.github/workflows/cpplint.yml
vendored
2
.github/workflows/cpplint.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install dependencies
|
||||
|
||||
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@ -3,6 +3,7 @@
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
"EditorConfig.EditorConfig",
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"platformio.platformio-ide"
|
||||
|
||||
35
README.md
35
README.md
@ -42,6 +42,10 @@ Please feel free to support and create a PR in [this](https://github.com/tbnobod
|
||||
Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | grep BREAKING`
|
||||
|
||||
```code
|
||||
* 1b637f08 2024-01-30 BREAKING CHANGE: Web API Endpoint /api/livedata/status and /api/prometheus/metrics
|
||||
* e1564780 2024-01-30 BREAKING CHANGE: Web API Endpoint /api/livedata/status and /api/prometheus/metrics
|
||||
* f0b5542c 2024-01-30 BREAKING CHANGE: Web API Endpoint /api/livedata/status and /api/prometheus/metrics
|
||||
* c27ecc36 2024-01-29 BREAKING CHANGE: Web API Endpoint /api/livedata/status
|
||||
* 71d1b3b 2023-11-07 BREAKING CHANGE: Home Assistant Auto Discovery to new naming scheme
|
||||
* 04f62e0 2023-04-20 BREAKING CHANGE: Web API Endpoint /api/eventlog/status no nested serial object
|
||||
* 59f43a8 2023-04-17 BREAKING CHANGE: Web API Endpoint /api/devinfo/status requires GET parameter inv=
|
||||
@ -90,34 +94,3 @@ Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | gre
|
||||
| TSUN TSOL-M350 | NRF24L01+ | 1 | 1 | 1 |
|
||||
| TSUN TSOL-M800 | NRF24L01+ | 2 | 2 | 1 |
|
||||
| TSUN TSOL-M1600 | NRF24L01+ | 4 | 2 | 1 |
|
||||
|
||||
|
||||
|
||||
## Hardware you need
|
||||
|
||||
### ESP32 board
|
||||
|
||||
For ease of use, buy a "ESP32 DEVKIT DOIT" or "ESP32 NodeMCU Development Board" with an ESP32-S3 or ESP-WROOM-32 chipset on it.
|
||||
|
||||
Sample Picture:
|
||||
|
||||

|
||||
|
||||
Also supported: Board with Ethernet-Connector and Power-over-Ethernet [Olimex ESP32-POE](https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware)
|
||||
|
||||
### Change pin assignment
|
||||
|
||||
Its possible to change all the pins of the NRF24L01+ module, the Display, the LED etc.
|
||||
The recommend way to change the pin assignment is by creating a custom [device profile](docs/DeviceProfiles.md).
|
||||
It is also possible to create a custom environment and compile the source yourself. This can be achieved by copying one of the [env:....] sections from 'platformio.ini' to 'platformio_override.ini' and editing the 'platformio_override.ini' file and add/change one or more of the following lines to the 'build_flags' parameter:
|
||||
|
||||
```makefile
|
||||
-DHOYMILES_PIN_MISO=19
|
||||
-DHOYMILES_PIN_MOSI=23
|
||||
-DHOYMILES_PIN_SCLK=18
|
||||
-DHOYMILES_PIN_IRQ=16
|
||||
-DHOYMILES_PIN_CE=4
|
||||
-DHOYMILES_PIN_CS=5
|
||||
```
|
||||
|
||||
It is recommended to make all changes only in the 'platformio_override.ini', this is your personal copy.
|
||||
|
||||
76
docs/DeviceProfiles/AhoyDTU-ESP32.json
Normal file
76
docs/DeviceProfiles/AhoyDTU-ESP32.json
Normal file
@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"name": "AhoyDTU ESP32 Display LED",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"led": {
|
||||
"led0": 25,
|
||||
"led1": 26
|
||||
},
|
||||
"display": {
|
||||
"type": 2,
|
||||
"data": 21,
|
||||
"clk": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32 Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"display": {
|
||||
"type": 2,
|
||||
"data": 21,
|
||||
"clk": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32 LED",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"led": {
|
||||
"led0": 25,
|
||||
"led1": 26
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
74
docs/DeviceProfiles/liligo_t-eth-lite_poe.json
Normal file
74
docs/DeviceProfiles/liligo_t-eth-lite_poe.json
Normal file
@ -0,0 +1,74 @@
|
||||
[
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE CMT",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"cmt": {
|
||||
"clk": 15,
|
||||
"cs": 32,
|
||||
"fcs": 33,
|
||||
"sdio": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE NRF24",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"nrf24": {
|
||||
"miso": 34,
|
||||
"mosi": 13,
|
||||
"clk": 14,
|
||||
"irq": 35,
|
||||
"en": 4,
|
||||
"cs": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE NRF24 + Display",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"nrf24": {
|
||||
"miso": 34,
|
||||
"mosi": 13,
|
||||
"clk": 14,
|
||||
"irq": 35,
|
||||
"en": 4,
|
||||
"cs": 2
|
||||
},
|
||||
"display": {
|
||||
"type": 3,
|
||||
"data": 32,
|
||||
"clk": 33
|
||||
}
|
||||
}
|
||||
]
|
||||
47
docs/DeviceProfiles/olimex_esp32_gateway.json
Normal file
47
docs/DeviceProfiles/olimex_esp32_gateway.json
Normal file
@ -0,0 +1,47 @@
|
||||
[
|
||||
{
|
||||
"name": "Olimex ESP32-Gateway",
|
||||
"nrf24": {
|
||||
"miso": 14,
|
||||
"mosi": 13,
|
||||
"clk": 12,
|
||||
"irq": 15,
|
||||
"en": 2,
|
||||
"cs": 4
|
||||
},
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 0,
|
||||
"clk_mode": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Olimex ESP32-Gateway with SSH1106",
|
||||
"nrf24": {
|
||||
"miso": 14,
|
||||
"mosi": 13,
|
||||
"clk": 12,
|
||||
"irq": 15,
|
||||
"en": 2,
|
||||
"cs": 4
|
||||
},
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 0,
|
||||
"clk_mode": 3
|
||||
},
|
||||
"display": {
|
||||
"type": 3,
|
||||
"data": 32,
|
||||
"clk": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,20 +1,3 @@
|
||||
# Display integration
|
||||
|
||||
OpenDTU currently supports 3 types of displays (SSD1306, SH1106 and PCD8544). Currently only displays with a resolution of 128x64 pixel are supported. To activate a display you have to specify it's type and pin assignment either in the `platformio_override.ini` or in a device profile. Due to the fact that device profiles work with the pre-compiled binary the following documentation will only cover the device profile method.
|
||||
|
||||
You can either create your own device profile as described [here](DeviceProfiles.md) or use some pre-defined. The pre-defined profiles can be found [here](DeviceProfiles/). You can simply open the json file with a text editor of your choice to view/edit the pin assignment.
|
||||
|
||||
## Uploading Device Profiles
|
||||
|
||||
Use the "Config Management" site to upload (Restore) the json file. Make sure to choose "Pin Mapping (pin_mapping.json)" in the combo box. After you click on restore the ESP will restart. At this point, the profile is not yet active. Please read the next chapter.
|
||||

|
||||
|
||||
## Selecting a Device Profile
|
||||
|
||||
After you uploaded the device profile you can select the profile in the "Device Manager" view. After a click on "Save" the ESP will be restarted and the pin assignment is active. At this point the display should already show something. Please see the next chapter for display settings.
|
||||

|
||||
|
||||
## Display Settings
|
||||
|
||||
Display settings can also be found in the "Device Manager".
|
||||

|
||||
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/hardware/display/>
|
||||
|
||||
@ -1,21 +1,3 @@
|
||||
# Upgrade Partition
|
||||
|
||||
To be able to install further updates you have to update the partition table of the ESP32. Doing so will **erase** all configuration data. Over The Air update using the web interface is **NOT** possible!
|
||||
|
||||
**So make sure you export a backup of your configuration files before continuing.**
|
||||
|
||||
There are several possibilities to update the partition table:
|
||||
|
||||
- Using Visual Studio Code or PlatformIO CLI
|
||||
|
||||
If you have already used Visual Studio Code or the `platformio` command you can use it again to install the latest version. The partition table is upgraded automatically.
|
||||
|
||||
- Any kind of flash interface
|
||||
|
||||
If you like to use any kind of flash interface like `esptool.py`, Espressif Flash Download Tool, ESP_Flasher or esptool-js you have to make sure to upload the provided .factory.bin file. It is important to enter the correct target address.
|
||||
|
||||
| Address | File |
|
||||
| ---------| ---------------------- |
|
||||
| 0x0 | opendtu-*.factory.bin |
|
||||
|
||||
After upgrading the ESP32 will open the intergrated access point (AP) again. Just connect to it using the default password ("openDTU42"). If you are connected, just visit <http://192.168.4.1> and enter the "Configuration Management". Recover the previously backuped config files.
|
||||
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/firmware/howto/upgrade_partition/>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#define CONFIG_FILENAME "/config.json"
|
||||
#define CONFIG_VERSION 0x00011a00 // 0.1.26 // make sure to clean all after change
|
||||
#define CONFIG_VERSION 0x00011b00 // 0.1.27 // make sure to clean all after change
|
||||
|
||||
#define WIFI_MAX_SSID_STRLEN 32
|
||||
#define WIFI_MAX_PASSWORD_STRLEN 64
|
||||
@ -129,6 +129,7 @@ struct CONFIG_T {
|
||||
struct {
|
||||
int8_t PaLevel;
|
||||
uint32_t Frequency;
|
||||
uint8_t CountryMode;
|
||||
} Cmt;
|
||||
} Dtu;
|
||||
|
||||
@ -143,7 +144,10 @@ struct CONFIG_T {
|
||||
uint8_t Rotation;
|
||||
uint8_t Contrast;
|
||||
uint8_t Language;
|
||||
uint32_t DiagramDuration;
|
||||
struct {
|
||||
uint32_t Duration;
|
||||
uint8_t Mode;
|
||||
} Diagram;
|
||||
} Display;
|
||||
|
||||
struct {
|
||||
@ -166,4 +170,4 @@ public:
|
||||
INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial);
|
||||
};
|
||||
|
||||
extern ConfigurationClass Configuration;
|
||||
extern ConfigurationClass Configuration;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
class DatastoreClass {
|
||||
public:
|
||||
DatastoreClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
// Sum of yield total of all enabled inverters, a inverter which is just disabled at night is also included
|
||||
@ -81,4 +82,4 @@ private:
|
||||
bool _isAtLeastOnePollEnabled = false;
|
||||
};
|
||||
|
||||
extern DatastoreClass Datastore;
|
||||
extern DatastoreClass Datastore;
|
||||
|
||||
@ -6,15 +6,31 @@
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <U8g2lib.h>
|
||||
|
||||
#define CHART_HEIGHT 20 // chart area hight in pixels
|
||||
#define CHART_WIDTH 47 // chart area width in pixels
|
||||
|
||||
// Left-Upper position of diagram is drawn
|
||||
// (text of Y-axis is display left of that pos)
|
||||
#define CHART_POSX 80
|
||||
#define CHART_POSY 0
|
||||
|
||||
enum DisplayType_t {
|
||||
None,
|
||||
PCD8544,
|
||||
SSD1306,
|
||||
SH1106,
|
||||
SSD1309,
|
||||
ST7567_GM12864I_59N,
|
||||
DisplayType_Max,
|
||||
};
|
||||
|
||||
enum DiagramMode_t {
|
||||
Off,
|
||||
Small,
|
||||
Fullscreen,
|
||||
DisplayMode_Max,
|
||||
};
|
||||
|
||||
class DisplayGraphicClass {
|
||||
public:
|
||||
DisplayGraphicClass();
|
||||
@ -25,6 +41,7 @@ public:
|
||||
void setStatus(const bool turnOn);
|
||||
void setOrientation(const uint8_t rotation = DISPLAY_ROTATION);
|
||||
void setLanguage(const uint8_t language);
|
||||
void setDiagramMode(DiagramMode_t mode);
|
||||
void setStartupDisplay();
|
||||
|
||||
DisplayGraphicDiagramClass& Diagram();
|
||||
@ -47,14 +64,15 @@ private:
|
||||
bool _displayTurnedOn;
|
||||
|
||||
DisplayType_t _display_type = DisplayType_t::None;
|
||||
DiagramMode_t _diagram_mode = DiagramMode_t::Off;
|
||||
uint8_t _display_language = DISPLAY_LANGUAGE;
|
||||
uint8_t _mExtra;
|
||||
uint16_t _period = 1000;
|
||||
uint16_t _interval = 60000; // interval at which to power save (milliseconds)
|
||||
const uint16_t _period = 1000;
|
||||
const uint16_t _interval = 60000; // interval at which to power save (milliseconds)
|
||||
uint32_t _previousMillis = 0;
|
||||
char _fmtText[32];
|
||||
bool _isLarge = false;
|
||||
uint8_t _lineOffsets[5];
|
||||
};
|
||||
|
||||
extern DisplayGraphicClass Display;
|
||||
extern DisplayGraphicClass Display;
|
||||
|
||||
@ -5,20 +5,14 @@
|
||||
#include <U8g2lib.h>
|
||||
#include <array>
|
||||
|
||||
#define CHART_HEIGHT 20 // chart area hight in pixels
|
||||
#define CHART_WIDTH 47 // chart area width in pixels
|
||||
|
||||
// Left-Upper position of diagram is drawn
|
||||
// (text of Y-axis is display left of that pos)
|
||||
#define DIAG_POSX 80
|
||||
#define DIAG_POSY 0
|
||||
#define MAX_DATAPOINTS 128
|
||||
|
||||
class DisplayGraphicDiagramClass {
|
||||
public:
|
||||
DisplayGraphicDiagramClass();
|
||||
|
||||
void init(Scheduler& scheduler, U8G2* display);
|
||||
void redraw(uint8_t screenSaverOffsetX);
|
||||
void redraw(uint8_t screenSaverOffsetX, uint8_t xPos, uint8_t yPos, uint8_t width, uint8_t height, bool isFullscreen);
|
||||
|
||||
void updatePeriod();
|
||||
|
||||
@ -26,15 +20,17 @@ private:
|
||||
void averageLoop();
|
||||
void dataPointLoop();
|
||||
|
||||
static uint32_t getSecondsPerDot();
|
||||
uint32_t getSecondsPerDot();
|
||||
|
||||
Task _averageTask;
|
||||
Task _dataPointTask;
|
||||
|
||||
U8G2* _display = nullptr;
|
||||
std::array<float, CHART_WIDTH> _graphValues = {};
|
||||
std::array<float, MAX_DATAPOINTS> _graphValues = {};
|
||||
uint8_t _graphValuesCount = 0;
|
||||
|
||||
uint8_t _chartWidth = MAX_DATAPOINTS;
|
||||
|
||||
float _iRunningAverage = 0;
|
||||
uint16_t _iRunningAverageCnt = 0;
|
||||
};
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
class InverterSettingsClass {
|
||||
public:
|
||||
InverterSettingsClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
|
||||
@ -1,33 +1,34 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <AsyncWebSocket.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Stream.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <mutex>
|
||||
|
||||
#define BUFFER_SIZE 500
|
||||
|
||||
class MessageOutputClass : public Print {
|
||||
public:
|
||||
void init(Scheduler& scheduler);
|
||||
size_t write(uint8_t c) override;
|
||||
size_t write(const uint8_t* buffer, size_t size) override;
|
||||
void register_ws_output(AsyncWebSocket* output);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
AsyncWebSocket* _ws = nullptr;
|
||||
char _buffer[BUFFER_SIZE];
|
||||
uint16_t _buff_pos = 0;
|
||||
uint32_t _lastSend = 0;
|
||||
bool _forceSend = false;
|
||||
|
||||
std::mutex _msgLock;
|
||||
};
|
||||
|
||||
extern MessageOutputClass MessageOutput;
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <AsyncWebSocket.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Stream.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <mutex>
|
||||
|
||||
#define BUFFER_SIZE 500
|
||||
|
||||
class MessageOutputClass : public Print {
|
||||
public:
|
||||
MessageOutputClass();
|
||||
void init(Scheduler& scheduler);
|
||||
size_t write(uint8_t c) override;
|
||||
size_t write(const uint8_t* buffer, size_t size) override;
|
||||
void register_ws_output(AsyncWebSocket* output);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
AsyncWebSocket* _ws = nullptr;
|
||||
char _buffer[BUFFER_SIZE];
|
||||
uint16_t _buff_pos = 0;
|
||||
uint32_t _lastSend = 0;
|
||||
bool _forceSend = false;
|
||||
|
||||
std::mutex _msgLock;
|
||||
};
|
||||
|
||||
extern MessageOutputClass MessageOutput;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
class MqttHandleDtuClass {
|
||||
public:
|
||||
MqttHandleDtuClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
@ -14,4 +15,4 @@ private:
|
||||
Task _loopTask;
|
||||
};
|
||||
|
||||
extern MqttHandleDtuClass MqttHandleDtu;
|
||||
extern MqttHandleDtuClass MqttHandleDtu;
|
||||
|
||||
@ -51,6 +51,7 @@ const byteAssign_fieldDeviceClass_t deviceFieldAssignment[] = {
|
||||
|
||||
class MqttHandleHassClass {
|
||||
public:
|
||||
MqttHandleHassClass();
|
||||
void init(Scheduler& scheduler);
|
||||
void publishConfig();
|
||||
void forceUpdate();
|
||||
@ -79,4 +80,4 @@ private:
|
||||
bool _updateForced = false;
|
||||
};
|
||||
|
||||
extern MqttHandleHassClass MqttHandleHass;
|
||||
extern MqttHandleHassClass MqttHandleHass;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
class MqttHandleInverterClass {
|
||||
public:
|
||||
MqttHandleInverterClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
static String getTopic(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId);
|
||||
@ -39,4 +40,4 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
extern MqttHandleInverterClass MqttHandleInverter;
|
||||
extern MqttHandleInverterClass MqttHandleInverter;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
class MqttHandleInverterTotalClass {
|
||||
public:
|
||||
MqttHandleInverterTotalClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
@ -13,4 +14,4 @@ private:
|
||||
Task _loopTask;
|
||||
};
|
||||
|
||||
extern MqttHandleInverterTotalClass MqttHandleInverterTotal;
|
||||
extern MqttHandleInverterTotalClass MqttHandleInverterTotal;
|
||||
|
||||
@ -11,4 +11,5 @@ public:
|
||||
static int getTimezoneOffset();
|
||||
static void restartDtu();
|
||||
static bool checkJsonAlloc(const DynamicJsonDocument& doc, const char* function, const uint16_t line);
|
||||
static void removeAllFiles();
|
||||
};
|
||||
|
||||
@ -39,10 +39,6 @@ public:
|
||||
static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!");
|
||||
|
||||
private:
|
||||
void loop();
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
AsyncWebServer _server;
|
||||
|
||||
WebApiConfigClass _webApiConfig;
|
||||
@ -68,4 +64,4 @@ private:
|
||||
WebApiDatabaseClass _webApiWsDatabase;
|
||||
};
|
||||
|
||||
extern WebApiClass WebApi;
|
||||
extern WebApiClass WebApi;
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiConfigClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onConfigGet(AsyncWebServerRequest* request);
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onConfigListGet(AsyncWebServerRequest* request);
|
||||
void onConfigUploadFinish(AsyncWebServerRequest* request);
|
||||
void onConfigUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -3,12 +3,13 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#define DATABASE_FILENAME "/database.bin"
|
||||
|
||||
class WebApiDatabaseClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
void loop();
|
||||
bool write(float energy);
|
||||
|
||||
|
||||
@ -2,15 +2,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiDeviceClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onDeviceAdminGet(AsyncWebServerRequest* request);
|
||||
void onDeviceAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,14 +2,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiDevInfoClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onDevInfoStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiDtuClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
WebApiDtuClass();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onDtuAdminGet(AsyncWebServerRequest* request);
|
||||
void onDtuAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
Task _applyDataTask;
|
||||
void applyDataTaskCb();
|
||||
};
|
||||
|
||||
@ -15,6 +15,7 @@ enum WebApiError {
|
||||
DtuPollZero,
|
||||
DtuInvalidPowerLevel,
|
||||
DtuInvalidCmtFrequency,
|
||||
DtuInvalidCmtCountry,
|
||||
|
||||
ConfigBase = 3000,
|
||||
ConfigNotDeleted,
|
||||
@ -89,4 +90,4 @@ enum WebApiError {
|
||||
|
||||
HardwareBase = 12000,
|
||||
HardwarePinMappingLength,
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,14 +2,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiEventlogClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onEventlogStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiFirmwareClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onFirmwareUpdateFinish(AsyncWebServerRequest* request);
|
||||
void onFirmwareUpdateUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiGridProfileClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onGridProfileStatus(AsyncWebServerRequest* request);
|
||||
void onGridProfileRawdata(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiInverterClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onInverterList(AsyncWebServerRequest* request);
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onInverterEdit(AsyncWebServerRequest* request);
|
||||
void onInverterDelete(AsyncWebServerRequest* request);
|
||||
void onInverterOrder(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiLimitClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onLimitStatus(AsyncWebServerRequest* request);
|
||||
void onLimitPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,14 +2,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiMaintenanceClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onRebootPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,19 +2,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
#define MQTT_JSON_DOC_SIZE 10240
|
||||
|
||||
class WebApiMqttClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onMqttStatus(AsyncWebServerRequest* request);
|
||||
void onMqttAdminGet(AsyncWebServerRequest* request);
|
||||
void onMqttAdminPost(AsyncWebServerRequest* request);
|
||||
String getTlsCertInfo(const char* cert);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,16 +2,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiNetworkClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onNetworkStatus(AsyncWebServerRequest* request);
|
||||
void onNetworkAdminGet(AsyncWebServerRequest* request);
|
||||
void onNetworkAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiNtpClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onNtpStatus(AsyncWebServerRequest* request);
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onNtpAdminPost(AsyncWebServerRequest* request);
|
||||
void onNtpTimeGet(AsyncWebServerRequest* request);
|
||||
void onNtpTimePost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,15 +2,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiPowerClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onPowerStatus(AsyncWebServerRequest* request);
|
||||
void onPowerPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Hoymiles.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <map>
|
||||
|
||||
class WebApiPrometheusClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onPrometheusMetricsGet(AsyncWebServerRequest* request);
|
||||
@ -17,8 +17,6 @@ private:
|
||||
|
||||
void addPanelInfo(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
|
||||
enum MetricType_t {
|
||||
NONE = 0,
|
||||
GAUGE,
|
||||
@ -47,4 +45,4 @@ private:
|
||||
{ FLD_EFF, MetricType_t::GAUGE },
|
||||
{ FLD_IRR, MetricType_t::GAUGE },
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,17 +2,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiSecurityClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onSecurityGet(AsyncWebServerRequest* request);
|
||||
void onSecurityPost(AsyncWebServerRequest* request);
|
||||
|
||||
void onAuthenticateGet(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,14 +2,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiSysstatusClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onSystemStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiWebappClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
void responseBinaryDataWithETagCache(AsyncWebServerRequest* request, const String &contentType, const String &contentEncoding, const uint8_t *content, size_t len);
|
||||
};
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
class WebApiWsConsoleClass {
|
||||
public:
|
||||
WebApiWsConsoleClass();
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
AsyncWebServer* _server;
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
uint32_t _lastWsCleanup = 0;
|
||||
};
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiWsConsoleClass {
|
||||
public:
|
||||
WebApiWsConsoleClass();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
Task _wsCleanupTask;
|
||||
void wsCleanupTaskCb();
|
||||
};
|
||||
|
||||
@ -1,30 +1,37 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "Configuration.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Hoymiles.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiWsLiveClass {
|
||||
public:
|
||||
WebApiWsLiveClass();
|
||||
void init(AsyncWebServer& server);
|
||||
void loop();
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void generateJsonResponse(JsonVariant& root);
|
||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic = "");
|
||||
void addTotalField(JsonObject& root, const String& name, const float value, const String& unit, const uint8_t digits);
|
||||
static void generateInverterCommonJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv);
|
||||
static void generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv);
|
||||
static void generateCommonJsonResponse(JsonVariant& root);
|
||||
|
||||
static void addField(JsonObject& root, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic = "");
|
||||
static void addTotalField(JsonObject& root, const String& name, const float value, const String& unit, const uint8_t digits);
|
||||
|
||||
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
uint32_t _lastWsPublish = 0;
|
||||
uint32_t _lastInvUpdateCheck = 0;
|
||||
uint32_t _lastWsCleanup = 0;
|
||||
uint32_t _newestInverterTimestamp = 0;
|
||||
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };
|
||||
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
||||
Task _wsCleanupTask;
|
||||
void wsCleanupTaskCb();
|
||||
|
||||
Task _sendDataTask;
|
||||
void sendDataTaskCb();
|
||||
};
|
||||
|
||||
@ -83,7 +83,8 @@
|
||||
#define DTU_POLL_INTERVAL 5U
|
||||
#define DTU_NRF_PA_LEVEL 0U
|
||||
#define DTU_CMT_PA_LEVEL 0
|
||||
#define DTU_CMT_FREQUENCY 865000U
|
||||
#define DTU_CMT_FREQUENCY 865000000U
|
||||
#define DTU_CMT_COUNTRY_MODE 0U
|
||||
|
||||
#define MQTT_HASS_ENABLED false
|
||||
#define MQTT_HASS_EXPIRE true
|
||||
@ -99,9 +100,10 @@
|
||||
#define DISPLAY_CONTRAST 60U
|
||||
#define DISPLAY_LANGUAGE 0U
|
||||
#define DISPLAY_DIAGRAM_DURATION (10UL * 60UL * 60UL)
|
||||
#define DISPLAY_DIAGRAM_MODE 1U
|
||||
|
||||
#define REACHABLE_THRESHOLD 2U
|
||||
|
||||
#define LED_BRIGHTNESS 100U
|
||||
|
||||
#define MAX_INVERTER_LIMIT 2250
|
||||
#define MAX_INVERTER_LIMIT 2250
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,96 +1,96 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a.h
|
||||
* @brief CMT2300A transceiver RF chip driver
|
||||
*
|
||||
* @version 1.3
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#ifndef __CMT2300A_H
|
||||
#define __CMT2300A_H
|
||||
|
||||
#include "cmt2300a_defs.h"
|
||||
#include "cmt2300a_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ENABLE_AUTO_SWITCH_CHIP_STATUS /* Enable the auto switch chip status */
|
||||
|
||||
/* ************************************************************************
|
||||
The following are for chip status controls.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_SoftReset(void);
|
||||
uint8_t CMT2300A_GetChipStatus(void);
|
||||
bool CMT2300A_AutoSwitchStatus(uint8_t nGoCmd);
|
||||
bool CMT2300A_GoSleep(void);
|
||||
bool CMT2300A_GoStby(void);
|
||||
bool CMT2300A_GoTFS(void);
|
||||
bool CMT2300A_GoRFS(void);
|
||||
bool CMT2300A_GoTx(void);
|
||||
bool CMT2300A_GoRx(void);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for chip interrupts, GPIO, FIFO operations.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_ConfigGpio(uint8_t nGpioSel);
|
||||
void CMT2300A_ConfigInterrupt(uint8_t nInt1Sel, uint8_t nInt2Sel);
|
||||
void CMT2300A_SetInterruptPolar(bool bActiveHigh);
|
||||
void CMT2300A_SetFifoThreshold(uint8_t nFifoThreshold);
|
||||
void CMT2300A_EnableAntennaSwitch(uint8_t nMode);
|
||||
void CMT2300A_EnableInterrupt(uint8_t nEnable);
|
||||
void CMT2300A_EnableRxFifoAutoClear(bool bEnable);
|
||||
void CMT2300A_EnableFifoMerge(bool bEnable);
|
||||
void CMT2300A_EnableReadFifo(void);
|
||||
void CMT2300A_EnableWriteFifo(void);
|
||||
void CMT2300A_RestoreFifo(void);
|
||||
uint8_t CMT2300A_ClearTxFifo(void);
|
||||
uint8_t CMT2300A_ClearRxFifo(void);
|
||||
uint8_t CMT2300A_ClearInterruptFlags(void);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for Tx DIN operations in direct mode.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_ConfigTxDin(uint8_t nDinSel);
|
||||
void CMT2300A_EnableTxDin(bool bEnable);
|
||||
void CMT2300A_EnableTxDinInvert(bool bEnable);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are general operations.
|
||||
* ************************************************************************ */
|
||||
bool CMT2300A_IsExist(void);
|
||||
uint8_t CMT2300A_GetRssiCode(void);
|
||||
int CMT2300A_GetRssiDBm(void);
|
||||
void CMT2300A_SetFrequencyChannel(uint8_t nChann);
|
||||
void CMT2300A_SetFrequencyStep(uint8_t nOffset);
|
||||
void CMT2300A_SetPayloadLength(uint16_t nLength);
|
||||
void CMT2300A_EnableLfosc(bool bEnable);
|
||||
void CMT2300A_EnableLfoscOutput(bool bEnable);
|
||||
void CMT2300A_EnableAfc(bool bEnable);
|
||||
void CMT2300A_SetAfcOvfTh(uint8_t afcOvfTh);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for chip initializes.
|
||||
* ************************************************************************ */
|
||||
bool CMT2300A_Init(void);
|
||||
bool CMT2300A_ConfigRegBank(uint8_t base_addr, const uint8_t bank[], uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a.h
|
||||
* @brief CMT2300A transceiver RF chip driver
|
||||
*
|
||||
* @version 1.3
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#ifndef __CMT2300A_H
|
||||
#define __CMT2300A_H
|
||||
|
||||
#include "cmt2300a_defs.h"
|
||||
#include "cmt2300a_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ENABLE_AUTO_SWITCH_CHIP_STATUS /* Enable the auto switch chip status */
|
||||
|
||||
/* ************************************************************************
|
||||
The following are for chip status controls.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_SoftReset(void);
|
||||
uint8_t CMT2300A_GetChipStatus(void);
|
||||
bool CMT2300A_AutoSwitchStatus(uint8_t nGoCmd);
|
||||
bool CMT2300A_GoSleep(void);
|
||||
bool CMT2300A_GoStby(void);
|
||||
bool CMT2300A_GoTFS(void);
|
||||
bool CMT2300A_GoRFS(void);
|
||||
bool CMT2300A_GoTx(void);
|
||||
bool CMT2300A_GoRx(void);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for chip interrupts, GPIO, FIFO operations.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_ConfigGpio(uint8_t nGpioSel);
|
||||
void CMT2300A_ConfigInterrupt(uint8_t nInt1Sel, uint8_t nInt2Sel);
|
||||
void CMT2300A_SetInterruptPolar(bool bActiveHigh);
|
||||
void CMT2300A_SetFifoThreshold(uint8_t nFifoThreshold);
|
||||
void CMT2300A_EnableAntennaSwitch(uint8_t nMode);
|
||||
void CMT2300A_EnableInterrupt(uint8_t nEnable);
|
||||
void CMT2300A_EnableRxFifoAutoClear(bool bEnable);
|
||||
void CMT2300A_EnableFifoMerge(bool bEnable);
|
||||
void CMT2300A_EnableReadFifo(void);
|
||||
void CMT2300A_EnableWriteFifo(void);
|
||||
void CMT2300A_RestoreFifo(void);
|
||||
uint8_t CMT2300A_ClearTxFifo(void);
|
||||
uint8_t CMT2300A_ClearRxFifo(void);
|
||||
uint8_t CMT2300A_ClearInterruptFlags(void);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for Tx DIN operations in direct mode.
|
||||
* ************************************************************************ */
|
||||
void CMT2300A_ConfigTxDin(uint8_t nDinSel);
|
||||
void CMT2300A_EnableTxDin(bool bEnable);
|
||||
void CMT2300A_EnableTxDinInvert(bool bEnable);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are general operations.
|
||||
* ************************************************************************ */
|
||||
bool CMT2300A_IsExist(void);
|
||||
uint8_t CMT2300A_GetRssiCode(void);
|
||||
int CMT2300A_GetRssiDBm(void);
|
||||
void CMT2300A_SetFrequencyChannel(const uint8_t nChann);
|
||||
void CMT2300A_SetFrequencyStep(uint8_t nOffset);
|
||||
void CMT2300A_SetPayloadLength(uint16_t nLength);
|
||||
void CMT2300A_EnableLfosc(bool bEnable);
|
||||
void CMT2300A_EnableLfoscOutput(bool bEnable);
|
||||
void CMT2300A_EnableAfc(bool bEnable);
|
||||
void CMT2300A_SetAfcOvfTh(uint8_t afcOvfTh);
|
||||
|
||||
/* ************************************************************************
|
||||
* The following are for chip initializes.
|
||||
* ************************************************************************ */
|
||||
bool CMT2300A_Init(void);
|
||||
bool CMT2300A_ConfigRegBank(uint8_t base_addr, const uint8_t bank[], uint8_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,76 +1,76 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a_hal.c
|
||||
* @brief CMT2300A hardware abstraction layer
|
||||
*
|
||||
* @version 1.2
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#include "cmt2300a_hal.h"
|
||||
#include "cmt_spi3.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_InitSpi
|
||||
* @desc Initializes the CMT2300A SPI interface.
|
||||
* *********************************************************/
|
||||
void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed)
|
||||
{
|
||||
cmt_spi3_init(pin_sdio, pin_clk, pin_cs, pin_fcs, spi_speed);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_ReadReg
|
||||
* @desc Read the CMT2300A register at the specified address.
|
||||
* @param addr: register address
|
||||
* @return Register value
|
||||
* *********************************************************/
|
||||
uint8_t CMT2300A_ReadReg(uint8_t addr)
|
||||
{
|
||||
return cmt_spi3_read(addr);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_WriteReg
|
||||
* @desc Write the CMT2300A register at the specified address.
|
||||
* @param addr: register address
|
||||
* dat: register value
|
||||
* *********************************************************/
|
||||
void CMT2300A_WriteReg(uint8_t addr, uint8_t dat)
|
||||
{
|
||||
cmt_spi3_write(addr, dat);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_ReadFifo
|
||||
* @desc Reads the contents of the CMT2300A FIFO.
|
||||
* @param buf: buffer where to copy the FIFO read data
|
||||
* len: number of bytes to be read from the FIFO
|
||||
* *********************************************************/
|
||||
void CMT2300A_ReadFifo(uint8_t buf[], uint16_t len)
|
||||
{
|
||||
cmt_spi3_read_fifo(buf, len);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_WriteFifo
|
||||
* @desc Writes the buffer contents to the CMT2300A FIFO.
|
||||
* @param buf: buffer containing data to be put on the FIFO
|
||||
* len: number of bytes to be written to the FIFO
|
||||
* *********************************************************/
|
||||
void CMT2300A_WriteFifo(const uint8_t buf[], uint16_t len)
|
||||
{
|
||||
cmt_spi3_write_fifo(buf, len);
|
||||
}
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a_hal.c
|
||||
* @brief CMT2300A hardware abstraction layer
|
||||
*
|
||||
* @version 1.2
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#include "cmt2300a_hal.h"
|
||||
#include "cmt_spi3.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_InitSpi
|
||||
* @desc Initializes the CMT2300A SPI interface.
|
||||
* *********************************************************/
|
||||
void CMT2300A_InitSpi(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const uint32_t spi_speed)
|
||||
{
|
||||
cmt_spi3_init(pin_sdio, pin_clk, pin_cs, pin_fcs, spi_speed);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_ReadReg
|
||||
* @desc Read the CMT2300A register at the specified address.
|
||||
* @param addr: register address
|
||||
* @return Register value
|
||||
* *********************************************************/
|
||||
uint8_t CMT2300A_ReadReg(const uint8_t addr)
|
||||
{
|
||||
return cmt_spi3_read(addr);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_WriteReg
|
||||
* @desc Write the CMT2300A register at the specified address.
|
||||
* @param addr: register address
|
||||
* dat: register value
|
||||
* *********************************************************/
|
||||
void CMT2300A_WriteReg(const uint8_t addr, const uint8_t dat)
|
||||
{
|
||||
cmt_spi3_write(addr, dat);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_ReadFifo
|
||||
* @desc Reads the contents of the CMT2300A FIFO.
|
||||
* @param buf: buffer where to copy the FIFO read data
|
||||
* len: number of bytes to be read from the FIFO
|
||||
* *********************************************************/
|
||||
void CMT2300A_ReadFifo(uint8_t buf[], const uint16_t len)
|
||||
{
|
||||
cmt_spi3_read_fifo(buf, len);
|
||||
}
|
||||
|
||||
/*! ********************************************************
|
||||
* @name CMT2300A_WriteFifo
|
||||
* @desc Writes the buffer contents to the CMT2300A FIFO.
|
||||
* @param buf: buffer containing data to be put on the FIFO
|
||||
* len: number of bytes to be written to the FIFO
|
||||
* *********************************************************/
|
||||
void CMT2300A_WriteFifo(const uint8_t buf[], const uint16_t len)
|
||||
{
|
||||
cmt_spi3_write_fifo(buf, len);
|
||||
}
|
||||
|
||||
@ -1,51 +1,51 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a_hal.h
|
||||
* @brief CMT2300A hardware abstraction layer
|
||||
*
|
||||
* @version 1.2
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#ifndef __CMT2300A_HAL_H
|
||||
#define __CMT2300A_HAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ************************************************************************
|
||||
* The following need to be modified by user
|
||||
* ************************************************************************ */
|
||||
#define CMT2300A_DelayMs(ms) delay(ms)
|
||||
#define CMT2300A_DelayUs(us) delayMicroseconds(us)
|
||||
#define CMT2300A_GetTickCount() millis()
|
||||
/* ************************************************************************ */
|
||||
|
||||
void CMT2300A_InitSpi(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed);
|
||||
|
||||
uint8_t CMT2300A_ReadReg(uint8_t addr);
|
||||
void CMT2300A_WriteReg(uint8_t addr, uint8_t dat);
|
||||
|
||||
void CMT2300A_ReadFifo(uint8_t buf[], uint16_t len);
|
||||
void CMT2300A_WriteFifo(const uint8_t buf[], uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, CMOSTEK SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) CMOSTEK SZ.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file cmt2300a_hal.h
|
||||
* @brief CMT2300A hardware abstraction layer
|
||||
*
|
||||
* @version 1.2
|
||||
* @date Jul 17 2017
|
||||
* @author CMOSTEK R@D
|
||||
*/
|
||||
|
||||
#ifndef __CMT2300A_HAL_H
|
||||
#define __CMT2300A_HAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ************************************************************************
|
||||
* The following need to be modified by user
|
||||
* ************************************************************************ */
|
||||
#define CMT2300A_DelayMs(ms) delay(ms)
|
||||
#define CMT2300A_DelayUs(us) delayMicroseconds(us)
|
||||
#define CMT2300A_GetTickCount() millis()
|
||||
/* ************************************************************************ */
|
||||
|
||||
void CMT2300A_InitSpi(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const uint32_t spi_speed);
|
||||
|
||||
uint8_t CMT2300A_ReadReg(const uint8_t addr);
|
||||
void CMT2300A_WriteReg(const uint8_t addr, const uint8_t dat);
|
||||
|
||||
void CMT2300A_ReadFifo(uint8_t buf[], const uint16_t len);
|
||||
void CMT2300A_WriteFifo(const uint8_t buf[], const uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -85,14 +85,14 @@
|
||||
; RSSI Offset = 0
|
||||
; RSSI Offset Sign = 0
|
||||
*/
|
||||
#ifndef __CMT2300A_PARAMS_H
|
||||
#define __CMT2300A_PARAMS_H
|
||||
#ifndef __CMT2300A_PARAMS_860_H
|
||||
#define __CMT2300A_PARAMS_860_H
|
||||
|
||||
#include "cmt2300a_defs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* [CMT Bank] with RSSI offset of +- 0 (and Tx power double bit not set) */
|
||||
static uint8_t g_cmt2300aCmtBank[CMT2300A_CMT_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aCmtBank_860[CMT2300A_CMT_BANK_SIZE] = {
|
||||
0x00,
|
||||
0x66,
|
||||
0xEC,
|
||||
@ -108,7 +108,7 @@ static uint8_t g_cmt2300aCmtBank[CMT2300A_CMT_BANK_SIZE] = {
|
||||
};
|
||||
|
||||
/* [System Bank] */
|
||||
static uint8_t g_cmt2300aSystemBank[CMT2300A_SYSTEM_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aSystemBank_860[CMT2300A_SYSTEM_BANK_SIZE] = {
|
||||
0xAE,
|
||||
0xE0,
|
||||
0x35,
|
||||
@ -124,7 +124,7 @@ static uint8_t g_cmt2300aSystemBank[CMT2300A_SYSTEM_BANK_SIZE] = {
|
||||
};
|
||||
|
||||
/* [Frequency Bank] 860 MHz */
|
||||
static uint8_t g_cmt2300aFrequencyBank[CMT2300A_FREQUENCY_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aFrequencyBank_860[CMT2300A_FREQUENCY_BANK_SIZE] = {
|
||||
0x42,
|
||||
0x32,
|
||||
0xCF,
|
||||
@ -136,7 +136,7 @@ static uint8_t g_cmt2300aFrequencyBank[CMT2300A_FREQUENCY_BANK_SIZE] = {
|
||||
};
|
||||
|
||||
/* [Data Rate Bank] */
|
||||
static uint8_t g_cmt2300aDataRateBank[CMT2300A_DATA_RATE_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aDataRateBank_860[CMT2300A_DATA_RATE_BANK_SIZE] = {
|
||||
0xA6,
|
||||
0xC9,
|
||||
0x20,
|
||||
@ -164,7 +164,7 @@ static uint8_t g_cmt2300aDataRateBank[CMT2300A_DATA_RATE_BANK_SIZE] = {
|
||||
};
|
||||
|
||||
/* [Baseband Bank] - EU */
|
||||
static uint8_t g_cmt2300aBasebandBank[CMT2300A_BASEBAND_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aBasebandBank_860[CMT2300A_BASEBAND_BANK_SIZE] = {
|
||||
0x12,
|
||||
0x1E,
|
||||
0x00,
|
||||
@ -197,7 +197,7 @@ static uint8_t g_cmt2300aBasebandBank[CMT2300A_BASEBAND_BANK_SIZE] = {
|
||||
};
|
||||
|
||||
/* [Tx Bank] 13 dBm */
|
||||
static uint8_t g_cmt2300aTxBank[CMT2300A_TX_BANK_SIZE] = {
|
||||
static uint8_t g_cmt2300aTxBank_860[CMT2300A_TX_BANK_SIZE] = {
|
||||
0x70,
|
||||
0x4D,
|
||||
0x06,
|
||||
214
lib/CMT2300a/cmt2300a_params_900.h
Normal file
214
lib/CMT2300a/cmt2300a_params_900.h
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
;---------------------------------------
|
||||
; CMT2300A Configuration File
|
||||
; Generated by CMOSTEK RFPDK 1.46
|
||||
; 2023.03.17 23:16
|
||||
;---------------------------------------
|
||||
; Mode = Advanced
|
||||
; Part Number = CMT2300A
|
||||
; Frequency = 900.000 MHz
|
||||
; Xtal Frequency = 26.0000 MHz
|
||||
; Demodulation = GFSK
|
||||
; AGC = On
|
||||
; Data Rate = 20.0 kbps
|
||||
; Deviation = 20.0 kHz
|
||||
; Tx Xtal Tol. = 20 ppm
|
||||
; Rx Xtal Tol. = 20 ppm
|
||||
; TRx Matching Network Type = 20 dBm
|
||||
; Tx Power = +13 dBm
|
||||
; Gaussian BT = 0.5
|
||||
; Bandwidth = Auto-Select kHz
|
||||
; CDR Type = Counting
|
||||
; CDR DR Range = NA
|
||||
; AFC = On
|
||||
; AFC Method = Auto-Select
|
||||
; Data Representation = 0:F-low 1:F-high
|
||||
; Rx Duty-Cycle = Off
|
||||
; Tx Duty-Cycle = Off
|
||||
; Sleep Timer = Off
|
||||
; Sleep Time = NA
|
||||
; Rx Timer = Off
|
||||
; Rx Time T1 = NA
|
||||
; Rx Time T2 = NA
|
||||
; Rx Exit State = STBY
|
||||
; Tx Exit State = STBY
|
||||
; SLP Mode = Disable
|
||||
; RSSI Valid Source = PJD
|
||||
; PJD Window = 8 Jumps
|
||||
; LFOSC Calibration = On
|
||||
; Xtal Stable Time = 155 us
|
||||
; RSSI Compare TH = NA
|
||||
; Data Mode = Packet
|
||||
; Whitening = Disable
|
||||
; Whiten Type = NA
|
||||
; Whiten Seed Type = NA
|
||||
; Whiten Seed = NA
|
||||
; Manchester = Disable
|
||||
; Manchester Type = NA
|
||||
; FEC = Enable
|
||||
; FEC Type = x^3+x^2+1
|
||||
; Tx Prefix Type = 0
|
||||
; Tx Packet Number = 1
|
||||
; Tx Packet Gap = 32
|
||||
; Packet Type = Variable Length
|
||||
; Node-Length Position = First Node, then Length
|
||||
; Payload Bit Order = Start from msb
|
||||
; Preamble Rx Size = 2
|
||||
; Preamble Tx Size = 30
|
||||
; Preamble Value = 170
|
||||
; Preamble Unit = 8-bit
|
||||
; Sync Size = 4-byte
|
||||
; Sync Value = 1296587336
|
||||
; Sync Tolerance = None
|
||||
; Sync Manchester = Disable
|
||||
; Node ID Size = NA
|
||||
; Node ID Value = NA
|
||||
; Node ID Mode = None
|
||||
; Node ID Err Mask = Disable
|
||||
; Node ID Free = Disable
|
||||
; Payload Length = 32
|
||||
; CRC Options = IBM-16
|
||||
; CRC Seed = 0 crc_seed
|
||||
; CRC Range = Entire Payload
|
||||
; CRC Swap = Start from MSB
|
||||
; CRC Bit Invert = Normal
|
||||
; CRC Bit Order = Start from bit 15
|
||||
; Dout Mute = Off
|
||||
; Dout Adjust Mode = Disable
|
||||
; Dout Adjust Percentage = NA
|
||||
; Collision Detect = Off
|
||||
; Collision Detect Offset = NA
|
||||
; RSSI Detect Mode = At PREAM_OK
|
||||
; RSSI Filter Setting = 32-tap
|
||||
; RF Performance = High
|
||||
; LBD Threshold = 2.4 V
|
||||
; RSSI Offset = 0
|
||||
; RSSI Offset Sign = 0
|
||||
*/
|
||||
#ifndef __CMT2300A_PARAMS_900_H
|
||||
#define __CMT2300A_PARAMS_900_H
|
||||
|
||||
#include "cmt2300a_defs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* [CMT Bank] with RSSI offset of +- 0 (and Tx power double bit not set) */
|
||||
static uint8_t g_cmt2300aCmtBank_900[CMT2300A_CMT_BANK_SIZE] = {
|
||||
0x00,
|
||||
0x66,
|
||||
0xEC,
|
||||
0x1C,
|
||||
0x70,
|
||||
0x80,
|
||||
0x14,
|
||||
0x08,
|
||||
0x11,
|
||||
0x02,
|
||||
0x02,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* [System Bank] */
|
||||
static uint8_t g_cmt2300aSystemBank_900[CMT2300A_SYSTEM_BANK_SIZE] = {
|
||||
0xAE,
|
||||
0xE0,
|
||||
0x35,
|
||||
0x00,
|
||||
0x00,
|
||||
0xF4,
|
||||
0x10,
|
||||
0xE2,
|
||||
0x42,
|
||||
0x20,
|
||||
0x0C,
|
||||
0x81,
|
||||
};
|
||||
|
||||
/* [Frequency Bank] 900 MHz */
|
||||
static uint8_t g_cmt2300aFrequencyBank_900[CMT2300A_FREQUENCY_BANK_SIZE] = {
|
||||
0x45,
|
||||
0x46,
|
||||
0x0A,
|
||||
0x84,
|
||||
0x45,
|
||||
0x3B,
|
||||
0xB1,
|
||||
0x13,
|
||||
};
|
||||
|
||||
/* [Data Rate Bank] */
|
||||
static uint8_t g_cmt2300aDataRateBank_900[CMT2300A_DATA_RATE_BANK_SIZE] = {
|
||||
0xA6,
|
||||
0xC9,
|
||||
0x20,
|
||||
0x20,
|
||||
0xD2,
|
||||
0x35,
|
||||
0x0C,
|
||||
0x0B,
|
||||
0x9F,
|
||||
0x4B,
|
||||
0x29,
|
||||
0x29,
|
||||
0xC0,
|
||||
0x14,
|
||||
0x05,
|
||||
0x53,
|
||||
0x10,
|
||||
0x00,
|
||||
0xB4,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
/* [Baseband Bank] - EU */
|
||||
static uint8_t g_cmt2300aBasebandBank_900[CMT2300A_BASEBAND_BANK_SIZE] = {
|
||||
0x12,
|
||||
0x1E,
|
||||
0x00,
|
||||
0xAA,
|
||||
0x06,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x48,
|
||||
0x5A,
|
||||
0x48,
|
||||
0x4D,
|
||||
0x01,
|
||||
0x1F,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xC3,
|
||||
0x00,
|
||||
0x00,
|
||||
0x60,
|
||||
0xFF,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1F,
|
||||
0x10,
|
||||
};
|
||||
|
||||
/* [Tx Bank] 13 dBm */
|
||||
static uint8_t g_cmt2300aTxBank_900[CMT2300A_TX_BANK_SIZE] = {
|
||||
0x70,
|
||||
0x4D,
|
||||
0x06,
|
||||
0x00,
|
||||
0x07,
|
||||
0x50,
|
||||
0x00,
|
||||
0x53,
|
||||
0x09,
|
||||
0x3F,
|
||||
0x7F,
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,12 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "cmt2300wrapper.h"
|
||||
#include "cmt2300a.h"
|
||||
#include "cmt2300a_params.h"
|
||||
#include "cmt2300a_params_860.h"
|
||||
#include "cmt2300a_params_900.h"
|
||||
|
||||
CMT2300A::CMT2300A(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t spi_speed)
|
||||
CMT2300A::CMT2300A(const uint8_t pin_sdio, const uint8_t pin_clk, const uint8_t pin_cs, const uint8_t pin_fcs, const uint32_t spi_speed)
|
||||
{
|
||||
_pin_sdio = pin_sdio;
|
||||
_pin_clk = pin_clk;
|
||||
@ -57,7 +58,7 @@ bool CMT2300A::available(void)
|
||||
) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG);
|
||||
}
|
||||
|
||||
void CMT2300A::read(void* buf, uint8_t len)
|
||||
void CMT2300A::read(void* buf, const uint8_t len)
|
||||
{
|
||||
// Fetch the payload
|
||||
CMT2300A_ReadFifo(static_cast<uint8_t*>(buf), len);
|
||||
@ -65,7 +66,7 @@ void CMT2300A::read(void* buf, uint8_t len)
|
||||
CMT2300A_ClearInterruptFlags();
|
||||
}
|
||||
|
||||
bool CMT2300A::write(const uint8_t* buf, uint8_t len)
|
||||
bool CMT2300A::write(const uint8_t* buf, const uint8_t len)
|
||||
{
|
||||
CMT2300A_GoStby();
|
||||
CMT2300A_ClearInterruptFlags();
|
||||
@ -100,7 +101,7 @@ bool CMT2300A::write(const uint8_t* buf, uint8_t len)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMT2300A::setChannel(uint8_t channel)
|
||||
void CMT2300A::setChannel(const uint8_t channel)
|
||||
{
|
||||
CMT2300A_SetFrequencyChannel(channel);
|
||||
}
|
||||
@ -122,7 +123,7 @@ int CMT2300A::getRssiDBm()
|
||||
return CMT2300A_GetRssiDBm();
|
||||
}
|
||||
|
||||
bool CMT2300A::setPALevel(int8_t level)
|
||||
bool CMT2300A::setPALevel(const int8_t level)
|
||||
{
|
||||
uint16_t Tx_dBm_word;
|
||||
switch (level) {
|
||||
@ -242,6 +243,22 @@ bool CMT2300A::rxFifoAvailable()
|
||||
) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG);
|
||||
}
|
||||
|
||||
uint32_t CMT2300A::getBaseFrequency() const
|
||||
{
|
||||
return getBaseFrequency(_frequencyBand);
|
||||
}
|
||||
|
||||
FrequencyBand_t CMT2300A::getFrequencyBand() const
|
||||
{
|
||||
return _frequencyBand;
|
||||
}
|
||||
|
||||
void CMT2300A::setFrequencyBand(const FrequencyBand_t mode)
|
||||
{
|
||||
_frequencyBand = mode;
|
||||
_init_radio();
|
||||
}
|
||||
|
||||
void CMT2300A::flush_rx(void)
|
||||
{
|
||||
CMT2300A_ClearRxFifo();
|
||||
@ -261,12 +278,24 @@ bool CMT2300A::_init_radio()
|
||||
}
|
||||
|
||||
/* config registers */
|
||||
CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank, CMT2300A_CMT_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank, CMT2300A_SYSTEM_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank, CMT2300A_FREQUENCY_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank, CMT2300A_DATA_RATE_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank, CMT2300A_BASEBAND_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank, CMT2300A_TX_BANK_SIZE);
|
||||
switch (_frequencyBand) {
|
||||
case FrequencyBand_t::BAND_900:
|
||||
CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank_900, CMT2300A_CMT_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank_900, CMT2300A_SYSTEM_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank_900, CMT2300A_FREQUENCY_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank_900, CMT2300A_DATA_RATE_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank_900, CMT2300A_BASEBAND_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank_900, CMT2300A_TX_BANK_SIZE);
|
||||
break;
|
||||
default:
|
||||
CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank_860, CMT2300A_CMT_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank_860, CMT2300A_SYSTEM_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank_860, CMT2300A_FREQUENCY_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank_860, CMT2300A_DATA_RATE_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank_860, CMT2300A_BASEBAND_BANK_SIZE);
|
||||
CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank_860, CMT2300A_TX_BANK_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
// xosc_aac_code[2:0] = 2
|
||||
uint8_t tmp;
|
||||
|
||||
@ -4,13 +4,21 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define CMT2300A_ONE_STEP_SIZE 2500 // frequency channel step size for fast frequency hopping operation: One step size is 2.5 kHz.
|
||||
#define CMT_BASE_FREQ 860000000 // from Frequency Bank in cmt2300a_params.h
|
||||
#define FH_OFFSET 100 // value * CMT2300A_ONE_STEP_SIZE = channel frequency offset
|
||||
#define CMT_SPI_SPEED 4000000 // 4 MHz
|
||||
|
||||
#define CMT_BASE_FREQ_900 900000000
|
||||
#define CMT_BASE_FREQ_860 860000000
|
||||
|
||||
enum FrequencyBand_t {
|
||||
BAND_860,
|
||||
BAND_900,
|
||||
FrequencyBand_Max,
|
||||
};
|
||||
|
||||
class CMT2300A {
|
||||
public:
|
||||
CMT2300A(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t _spi_speed = CMT_SPI_SPEED);
|
||||
CMT2300A(const uint8_t pin_sdio, const uint8_t pin_clk, const uint8_t pin_cs, const uint8_t pin_fcs, const uint32_t _spi_speed = CMT_SPI_SPEED);
|
||||
|
||||
bool begin(void);
|
||||
|
||||
@ -54,15 +62,15 @@ public:
|
||||
* in one call is 32 (for dynamic payload lengths) or whatever number was
|
||||
* previously passed to setPayloadSize() (for static payload lengths).
|
||||
*/
|
||||
void read(void* buf, uint8_t len);
|
||||
void read(void* buf, const uint8_t len);
|
||||
|
||||
bool write(const uint8_t* buf, uint8_t len);
|
||||
bool write(const uint8_t* buf, const uint8_t len);
|
||||
|
||||
/**
|
||||
* Set RF communication channel. The frequency used by a channel is
|
||||
* @param channel Which RF channel to communicate on, 0-254
|
||||
*/
|
||||
void setChannel(uint8_t channel);
|
||||
void setChannel(const uint8_t channel);
|
||||
|
||||
/**
|
||||
* Get RF communication channel
|
||||
@ -82,10 +90,26 @@ public:
|
||||
|
||||
int getRssiDBm();
|
||||
|
||||
bool setPALevel(int8_t level);
|
||||
bool setPALevel(const int8_t level);
|
||||
|
||||
bool rxFifoAvailable();
|
||||
|
||||
uint32_t getBaseFrequency() const;
|
||||
static constexpr uint32_t getBaseFrequency(FrequencyBand_t band)
|
||||
{
|
||||
switch (band) {
|
||||
case FrequencyBand_t::BAND_900:
|
||||
return CMT_BASE_FREQ_900;
|
||||
break;
|
||||
default:
|
||||
return CMT_BASE_FREQ_860;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FrequencyBand_t getFrequencyBand() const;
|
||||
void setFrequencyBand(const FrequencyBand_t mode);
|
||||
|
||||
/**
|
||||
* Empty the RX (receive) FIFO buffers.
|
||||
*/
|
||||
@ -109,4 +133,6 @@ private:
|
||||
int8_t _pin_cs;
|
||||
int8_t _pin_fcs;
|
||||
uint32_t _spi_speed;
|
||||
};
|
||||
|
||||
FrequencyBand_t _frequencyBand = FrequencyBand_t::BAND_860;
|
||||
};
|
||||
|
||||
@ -1,142 +1,142 @@
|
||||
#include "cmt_spi3.h"
|
||||
#include <Arduino.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_rom_gpio.h> // for esp_rom_gpio_connect_out_signal
|
||||
|
||||
SemaphoreHandle_t paramLock = NULL;
|
||||
#define SPI_PARAM_LOCK() \
|
||||
do { \
|
||||
} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
|
||||
|
||||
// for ESP32 this is the so-called HSPI
|
||||
// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore,
|
||||
// it is simply the first externally usable hardware SPI master controller
|
||||
#define SPI_CMT SPI2_HOST
|
||||
|
||||
spi_device_handle_t spi_reg, spi_fifo;
|
||||
|
||||
void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed)
|
||||
{
|
||||
paramLock = xSemaphoreCreateMutex();
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = pin_sdio,
|
||||
.miso_io_num = -1, // single wire MOSI/MISO
|
||||
.sclk_io_num = pin_clk,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 32,
|
||||
};
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.dummy_bits = 0,
|
||||
.mode = 0, // SPI mode 0
|
||||
.cs_ena_pretrans = 1,
|
||||
.cs_ena_posttrans = 1,
|
||||
.clock_speed_hz = spi_speed,
|
||||
.spics_io_num = pin_cs,
|
||||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
|
||||
.queue_size = 1,
|
||||
.pre_cb = NULL,
|
||||
.post_cb = NULL,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI_CMT, &buscfg, SPI_DMA_DISABLED));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg, &spi_reg));
|
||||
|
||||
// FiFo
|
||||
spi_device_interface_config_t devcfg2 = {
|
||||
.command_bits = 0,
|
||||
.address_bits = 0,
|
||||
.dummy_bits = 0,
|
||||
.mode = 0, // SPI mode 0
|
||||
.cs_ena_pretrans = 2,
|
||||
.cs_ena_posttrans = (uint8_t)(1 / (spi_speed * 10e6 * 2) + 2), // >2 us
|
||||
.clock_speed_hz = spi_speed,
|
||||
.spics_io_num = pin_fcs,
|
||||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
|
||||
.queue_size = 1,
|
||||
.pre_cb = NULL,
|
||||
.post_cb = NULL,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg2, &spi_fifo));
|
||||
|
||||
esp_rom_gpio_connect_out_signal(pin_sdio, spi_periph_signal[SPI_CMT].spid_out, true, false);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void cmt_spi3_write(uint8_t addr, uint8_t dat)
|
||||
{
|
||||
uint8_t tx_data;
|
||||
tx_data = ~dat;
|
||||
spi_transaction_t t = {
|
||||
.cmd = 1,
|
||||
.addr = ~addr,
|
||||
.length = 8,
|
||||
.tx_buffer = &tx_data,
|
||||
.rx_buffer = NULL
|
||||
};
|
||||
SPI_PARAM_LOCK();
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||
SPI_PARAM_UNLOCK();
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
uint8_t cmt_spi3_read(uint8_t addr)
|
||||
{
|
||||
uint8_t rx_data;
|
||||
spi_transaction_t t = {
|
||||
.cmd = 0,
|
||||
.addr = ~addr,
|
||||
.length = 8,
|
||||
.rxlength = 8,
|
||||
.tx_buffer = NULL,
|
||||
.rx_buffer = &rx_data
|
||||
};
|
||||
SPI_PARAM_LOCK();
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||
SPI_PARAM_UNLOCK();
|
||||
delayMicroseconds(100);
|
||||
return rx_data;
|
||||
}
|
||||
|
||||
void cmt_spi3_write_fifo(const uint8_t* buf, uint16_t len)
|
||||
{
|
||||
uint8_t tx_data;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.tx_buffer = &tx_data, // reference to write data
|
||||
.rx_buffer = NULL
|
||||
};
|
||||
|
||||
SPI_PARAM_LOCK();
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
tx_data = ~buf[i]; // negate buffer contents
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||
delayMicroseconds(4); // > 4 us
|
||||
}
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
|
||||
void cmt_spi3_read_fifo(uint8_t* buf, uint16_t len)
|
||||
{
|
||||
uint8_t rx_data;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.rxlength = 8,
|
||||
.tx_buffer = NULL,
|
||||
.rx_buffer = &rx_data
|
||||
};
|
||||
|
||||
SPI_PARAM_LOCK();
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||
delayMicroseconds(4); // > 4 us
|
||||
buf[i] = rx_data;
|
||||
}
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
#include "cmt_spi3.h"
|
||||
#include <Arduino.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_rom_gpio.h> // for esp_rom_gpio_connect_out_signal
|
||||
|
||||
SemaphoreHandle_t paramLock = NULL;
|
||||
#define SPI_PARAM_LOCK() \
|
||||
do { \
|
||||
} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
|
||||
|
||||
// for ESP32 this is the so-called HSPI
|
||||
// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore,
|
||||
// it is simply the first externally usable hardware SPI master controller
|
||||
#define SPI_CMT SPI2_HOST
|
||||
|
||||
spi_device_handle_t spi_reg, spi_fifo;
|
||||
|
||||
void cmt_spi3_init(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const uint32_t spi_speed)
|
||||
{
|
||||
paramLock = xSemaphoreCreateMutex();
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = pin_sdio,
|
||||
.miso_io_num = -1, // single wire MOSI/MISO
|
||||
.sclk_io_num = pin_clk,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 32,
|
||||
};
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.dummy_bits = 0,
|
||||
.mode = 0, // SPI mode 0
|
||||
.cs_ena_pretrans = 1,
|
||||
.cs_ena_posttrans = 1,
|
||||
.clock_speed_hz = spi_speed,
|
||||
.spics_io_num = pin_cs,
|
||||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
|
||||
.queue_size = 1,
|
||||
.pre_cb = NULL,
|
||||
.post_cb = NULL,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI_CMT, &buscfg, SPI_DMA_DISABLED));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg, &spi_reg));
|
||||
|
||||
// FiFo
|
||||
spi_device_interface_config_t devcfg2 = {
|
||||
.command_bits = 0,
|
||||
.address_bits = 0,
|
||||
.dummy_bits = 0,
|
||||
.mode = 0, // SPI mode 0
|
||||
.cs_ena_pretrans = 2,
|
||||
.cs_ena_posttrans = (uint8_t)(1 / (spi_speed * 10e6 * 2) + 2), // >2 us
|
||||
.clock_speed_hz = spi_speed,
|
||||
.spics_io_num = pin_fcs,
|
||||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
|
||||
.queue_size = 1,
|
||||
.pre_cb = NULL,
|
||||
.post_cb = NULL,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg2, &spi_fifo));
|
||||
|
||||
esp_rom_gpio_connect_out_signal(pin_sdio, spi_periph_signal[SPI_CMT].spid_out, true, false);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void cmt_spi3_write(const uint8_t addr, const uint8_t dat)
|
||||
{
|
||||
uint8_t tx_data;
|
||||
tx_data = ~dat;
|
||||
spi_transaction_t t = {
|
||||
.cmd = 1,
|
||||
.addr = ~addr,
|
||||
.length = 8,
|
||||
.tx_buffer = &tx_data,
|
||||
.rx_buffer = NULL
|
||||
};
|
||||
SPI_PARAM_LOCK();
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||
SPI_PARAM_UNLOCK();
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
uint8_t cmt_spi3_read(const uint8_t addr)
|
||||
{
|
||||
uint8_t rx_data;
|
||||
spi_transaction_t t = {
|
||||
.cmd = 0,
|
||||
.addr = ~addr,
|
||||
.length = 8,
|
||||
.rxlength = 8,
|
||||
.tx_buffer = NULL,
|
||||
.rx_buffer = &rx_data
|
||||
};
|
||||
SPI_PARAM_LOCK();
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||
SPI_PARAM_UNLOCK();
|
||||
delayMicroseconds(100);
|
||||
return rx_data;
|
||||
}
|
||||
|
||||
void cmt_spi3_write_fifo(const uint8_t* buf, const uint16_t len)
|
||||
{
|
||||
uint8_t tx_data;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.tx_buffer = &tx_data, // reference to write data
|
||||
.rx_buffer = NULL
|
||||
};
|
||||
|
||||
SPI_PARAM_LOCK();
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
tx_data = ~buf[i]; // negate buffer contents
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||
delayMicroseconds(4); // > 4 us
|
||||
}
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
|
||||
void cmt_spi3_read_fifo(uint8_t* buf, const uint16_t len)
|
||||
{
|
||||
uint8_t rx_data;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.rxlength = 8,
|
||||
.tx_buffer = NULL,
|
||||
.rx_buffer = &rx_data
|
||||
};
|
||||
|
||||
SPI_PARAM_LOCK();
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||
delayMicroseconds(4); // > 4 us
|
||||
buf[i] = rx_data;
|
||||
}
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#ifndef __CMT_SPI3_H
|
||||
#define __CMT_SPI3_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void cmt_spi3_init(int8_t pin_sdio, int8_t pin_clk, int8_t pin_cs, int8_t pin_fcs, uint32_t spi_speed);
|
||||
|
||||
void cmt_spi3_write(uint8_t addr, uint8_t dat);
|
||||
uint8_t cmt_spi3_read(uint8_t addr);
|
||||
|
||||
void cmt_spi3_write_fifo(const uint8_t* p_buf, uint16_t len);
|
||||
void cmt_spi3_read_fifo(uint8_t* p_buf, uint16_t len);
|
||||
|
||||
#endif
|
||||
#ifndef __CMT_SPI3_H
|
||||
#define __CMT_SPI3_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void cmt_spi3_init(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const uint32_t spi_speed);
|
||||
|
||||
void cmt_spi3_write(const uint8_t addr, const uint8_t dat);
|
||||
uint8_t cmt_spi3_read(const uint8_t addr);
|
||||
|
||||
void cmt_spi3_write_fifo(const uint8_t* p_buf, const uint16_t len);
|
||||
void cmt_spi3_read_fifo(uint8_t* p_buf, const uint16_t len);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,49 +1,79 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HoymilesRadio_CMT.h"
|
||||
#include "Hoymiles.h"
|
||||
#include "crc.h"
|
||||
#include <FunctionalInterrupt.h>
|
||||
#include <frozen/map.h>
|
||||
|
||||
#define HOY_BOOT_FREQ 868000000 // Hoymiles boot/init frequency after power up inverter or connection lost for 15 min
|
||||
#define HOY_BASE_FREQ 860000000
|
||||
// offset from initalized CMT base frequency to Hoy base frequency in channels
|
||||
#define CMT_BASE_CH_OFFSET860 ((CMT_BASE_FREQ - HOY_BASE_FREQ) / CMT2300A_ONE_STEP_SIZE / FH_OFFSET)
|
||||
|
||||
// frequency can not be lower than actual initailized base freq
|
||||
#define MIN_FREQ_KHZ ((HOY_BASE_FREQ + (CMT_BASE_CH_OFFSET860 >= 1 ? CMT_BASE_CH_OFFSET860 : 1) * CMT2300A_ONE_STEP_SIZE * FH_OFFSET) / 1000)
|
||||
|
||||
// =923500, 0xFF does not work
|
||||
#define MAX_FREQ_KHZ ((HOY_BASE_FREQ + 0xFE * CMT2300A_ONE_STEP_SIZE * FH_OFFSET) / 1000)
|
||||
|
||||
float HoymilesRadio_CMT::getFrequencyFromChannel(const uint8_t channel)
|
||||
constexpr CountryFrequencyDefinition_t make_value(FrequencyBand_t Band, uint32_t Freq_Legal_Min, uint32_t Freq_Legal_Max, uint32_t Freq_Default, uint32_t Freq_StartUp)
|
||||
{
|
||||
return (CMT_BASE_FREQ + (CMT_BASE_CH_OFFSET860 + channel) * FH_OFFSET * CMT2300A_ONE_STEP_SIZE) / 1000000.0;
|
||||
// frequency can not be lower than actual initailized base freq + 250000
|
||||
uint32_t minFrequency = CMT2300A::getBaseFrequency(Band) + HoymilesRadio_CMT::getChannelWidth();
|
||||
|
||||
// =923500, 0xFF does not work
|
||||
uint32_t maxFrequency = CMT2300A::getBaseFrequency(Band) + 0xFE * HoymilesRadio_CMT::getChannelWidth();
|
||||
|
||||
CountryFrequencyDefinition_t v = { Band, minFrequency, maxFrequency, Freq_Legal_Min, Freq_Legal_Max, Freq_Default, Freq_StartUp };
|
||||
return v;
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio_CMT::getChannelFromFrequency(const uint32_t freq_kHz)
|
||||
constexpr frozen::map<CountryModeId_t, CountryFrequencyDefinition_t, 3> countryDefinition = {
|
||||
{ CountryModeId_t::MODE_EU, make_value(FrequencyBand_t::BAND_860, 863e6, 870e6, 865e6, 868e6) },
|
||||
{ CountryModeId_t::MODE_US, make_value(FrequencyBand_t::BAND_900, 905e6, 925e6, 918e6, 915e6) },
|
||||
{ CountryModeId_t::MODE_BR, make_value(FrequencyBand_t::BAND_900, 915e6, 928e6, 918e6, 915e6) },
|
||||
};
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getFrequencyFromChannel(const uint8_t channel) const
|
||||
{
|
||||
if ((freq_kHz % 250) != 0) {
|
||||
Hoymiles.getMessageOutput()->printf("%.3f MHz is not divisible by 250 kHz!\r\n", freq_kHz / 1000.0);
|
||||
return (_radio->getBaseFrequency() + channel * getChannelWidth());
|
||||
}
|
||||
|
||||
uint8_t HoymilesRadio_CMT::getChannelFromFrequency(const uint32_t frequency) const
|
||||
{
|
||||
if ((frequency % getChannelWidth()) != 0) {
|
||||
Hoymiles.getMessageOutput()->printf("%.3f MHz is not divisible by %d kHz!\r\n", frequency / 1000000.0, getChannelWidth());
|
||||
return 0xFF; // ERROR
|
||||
}
|
||||
if (freq_kHz < MIN_FREQ_KHZ || freq_kHz > MAX_FREQ_KHZ) {
|
||||
if (frequency < getMinFrequency() || frequency > getMaxFrequency()) {
|
||||
Hoymiles.getMessageOutput()->printf("%.2f MHz is out of Hoymiles/CMT range! (%.2f MHz - %.2f MHz)\r\n",
|
||||
freq_kHz / 1000.0, MIN_FREQ_KHZ / 1000.0, MAX_FREQ_KHZ / 1000.0);
|
||||
frequency / 1000000.0, getMinFrequency() / 1000000.0, getMaxFrequency() / 1000000.0);
|
||||
return 0xFF; // ERROR
|
||||
}
|
||||
if (freq_kHz < 863000 || freq_kHz > 870000) {
|
||||
Hoymiles.getMessageOutput()->printf("!!! caution: %.2f MHz is out of EU legal range! (863 - 870 MHz)\r\n",
|
||||
freq_kHz / 1000.0);
|
||||
if (frequency < countryDefinition.at(_countryMode).Freq_Legal_Min || frequency > countryDefinition.at(_countryMode).Freq_Legal_Max) {
|
||||
Hoymiles.getMessageOutput()->printf("!!! caution: %.2f MHz is out of region legal range! (%d - %d MHz)\r\n",
|
||||
frequency / 1000000.0,
|
||||
static_cast<uint32_t>(countryDefinition.at(_countryMode).Freq_Legal_Min / 1e6),
|
||||
static_cast<uint32_t>(countryDefinition.at(_countryMode).Freq_Legal_Max / 1e6));
|
||||
}
|
||||
return (freq_kHz * 1000 - CMT_BASE_FREQ) / CMT2300A_ONE_STEP_SIZE / FH_OFFSET - CMT_BASE_CH_OFFSET860; // frequency to channel
|
||||
|
||||
return (frequency - _radio->getBaseFrequency()) / getChannelWidth(); // frequency to channel
|
||||
}
|
||||
|
||||
bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_freq_kHz)
|
||||
std::vector<CountryFrequencyList_t> HoymilesRadio_CMT::getCountryFrequencyList() const
|
||||
{
|
||||
const uint8_t toChannel = getChannelFromFrequency(to_freq_kHz);
|
||||
std::vector<CountryFrequencyList_t> v;
|
||||
for (const auto& [key, value] : countryDefinition) {
|
||||
CountryFrequencyList_t s;
|
||||
s.mode = key;
|
||||
s.definition.Band = value.Band;
|
||||
s.definition.Freq_Default = value.Freq_Default;
|
||||
s.definition.Freq_StartUp = value.Freq_StartUp;
|
||||
s.definition.Freq_Min = value.Freq_Min;
|
||||
s.definition.Freq_Max = value.Freq_Max;
|
||||
s.definition.Freq_Legal_Max = value.Freq_Legal_Max;
|
||||
s.definition.Freq_Legal_Min = value.Freq_Legal_Min;
|
||||
|
||||
v.push_back(s);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_frequency)
|
||||
{
|
||||
const uint8_t toChannel = getChannelFromFrequency(to_frequency);
|
||||
if (toChannel == 0xFF) {
|
||||
return false;
|
||||
}
|
||||
@ -61,6 +91,7 @@ void HoymilesRadio_CMT::init(const int8_t pin_sdio, const int8_t pin_clk, const
|
||||
|
||||
_radio->begin();
|
||||
|
||||
setCountryMode(CountryModeId_t::MODE_EU);
|
||||
cmtSwitchDtuFreq(_inverterTargetFrequency); // start dtu at work freqency, for fast Rx if inverter is already on and frequency switched
|
||||
|
||||
if (!_radio->isChipConnected()) {
|
||||
@ -134,7 +165,7 @@ void HoymilesRadio_CMT::loop()
|
||||
|
||||
if (nullptr != inv) {
|
||||
// Save packet in inverter rx buffer
|
||||
Hoymiles.getMessageOutput()->printf("RX %.2f MHz --> ", getFrequencyFromChannel(f.channel));
|
||||
Hoymiles.getMessageOutput()->printf("RX %.2f MHz --> ", getFrequencyFromChannel(f.channel) / 1000000.0);
|
||||
dumpBuf(f.fragment, f.len, false);
|
||||
Hoymiles.getMessageOutput()->printf("| %d dBm\r\n", f.rssi);
|
||||
|
||||
@ -191,14 +222,34 @@ bool HoymilesRadio_CMT::isConnected() const
|
||||
return _radio->isChipConnected();
|
||||
}
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getMinFrequency()
|
||||
uint32_t HoymilesRadio_CMT::getMinFrequency() const
|
||||
{
|
||||
return MIN_FREQ_KHZ;
|
||||
return countryDefinition.at(_countryMode).Freq_Min;
|
||||
}
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getMaxFrequency()
|
||||
uint32_t HoymilesRadio_CMT::getMaxFrequency() const
|
||||
{
|
||||
return MAX_FREQ_KHZ;
|
||||
return countryDefinition.at(_countryMode).Freq_Max;
|
||||
}
|
||||
|
||||
CountryModeId_t HoymilesRadio_CMT::getCountryMode() const
|
||||
{
|
||||
return _countryMode;
|
||||
}
|
||||
|
||||
void HoymilesRadio_CMT::setCountryMode(const CountryModeId_t mode)
|
||||
{
|
||||
_countryMode = mode;
|
||||
if (!_isInitialized) {
|
||||
return;
|
||||
}
|
||||
_radio->setFrequencyBand(countryDefinition.at(mode).Band);
|
||||
}
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getInvBootFrequency() const
|
||||
{
|
||||
// Hoymiles boot/init frequency after power up inverter or connection lost for 15 min
|
||||
return countryDefinition.at(_countryMode).Freq_StartUp;
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleInt1()
|
||||
@ -220,11 +271,11 @@ void HoymilesRadio_CMT::sendEsbPacket(CommandAbstract& cmd)
|
||||
_radio->stopListening();
|
||||
|
||||
if (cmd.getDataPayload()[0] == 0x56) { // @todo(tbnobody) Bad hack to identify ChannelChange Command
|
||||
cmtSwitchDtuFreq(HOY_BOOT_FREQ / 1000);
|
||||
cmtSwitchDtuFreq(getInvBootFrequency());
|
||||
}
|
||||
|
||||
Hoymiles.getMessageOutput()->printf("TX %s %.2f MHz --> ",
|
||||
cmd.getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel()));
|
||||
cmd.getCommandName().c_str(), getFrequencyFromChannel(_radio->getChannel()) / 1000000.0);
|
||||
cmd.dumpDataPayload(Hoymiles.getMessageOutput());
|
||||
|
||||
if (!_radio->write(cmd.getDataPayload(), cmd.getDataSize())) {
|
||||
|
||||
@ -8,14 +8,37 @@
|
||||
#include <cmt2300wrapper.h>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
// number of fragments hold in buffer
|
||||
#define FRAGMENT_BUFFER_SIZE 30
|
||||
|
||||
#ifndef HOYMILES_CMT_WORK_FREQ
|
||||
#define HOYMILES_CMT_WORK_FREQ 865000
|
||||
#define HOYMILES_CMT_WORK_FREQ 865000000
|
||||
#endif
|
||||
|
||||
enum CountryModeId_t {
|
||||
MODE_EU,
|
||||
MODE_US,
|
||||
MODE_BR,
|
||||
CountryModeId_Max
|
||||
};
|
||||
|
||||
struct CountryFrequencyDefinition_t {
|
||||
FrequencyBand_t Band;
|
||||
uint32_t Freq_Min;
|
||||
uint32_t Freq_Max;
|
||||
uint32_t Freq_Legal_Min;
|
||||
uint32_t Freq_Legal_Max;
|
||||
uint32_t Freq_Default;
|
||||
uint32_t Freq_StartUp;
|
||||
};
|
||||
|
||||
struct CountryFrequencyList_t {
|
||||
CountryModeId_t mode;
|
||||
CountryFrequencyDefinition_t definition;
|
||||
};
|
||||
|
||||
class HoymilesRadio_CMT : public HoymilesRadio {
|
||||
public:
|
||||
void init(const int8_t pin_sdio, const int8_t pin_clk, const int8_t pin_cs, const int8_t pin_fcs, const int8_t pin_gpio2, const int8_t pin_gpio3);
|
||||
@ -26,11 +49,22 @@ public:
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
static uint32_t getMinFrequency();
|
||||
static uint32_t getMaxFrequency();
|
||||
uint32_t getMinFrequency() const;
|
||||
uint32_t getMaxFrequency() const;
|
||||
static constexpr uint32_t getChannelWidth()
|
||||
{
|
||||
return FH_OFFSET * CMT2300A_ONE_STEP_SIZE;
|
||||
}
|
||||
|
||||
static float getFrequencyFromChannel(const uint8_t channel);
|
||||
static uint8_t getChannelFromFrequency(const uint32_t freq_kHz);
|
||||
CountryModeId_t getCountryMode() const;
|
||||
void setCountryMode(const CountryModeId_t mode);
|
||||
|
||||
uint32_t getInvBootFrequency() const;
|
||||
|
||||
uint32_t getFrequencyFromChannel(const uint8_t channel) const;
|
||||
uint8_t getChannelFromFrequency(const uint32_t frequency) const;
|
||||
|
||||
std::vector<CountryFrequencyList_t> getCountryFrequencyList() const;
|
||||
|
||||
private:
|
||||
void ARDUINO_ISR_ATTR handleInt1();
|
||||
@ -51,5 +85,7 @@ private:
|
||||
|
||||
uint32_t _inverterTargetFrequency = HOYMILES_CMT_WORK_FREQ;
|
||||
|
||||
bool cmtSwitchDtuFreq(const uint32_t to_freq_kHz);
|
||||
};
|
||||
bool cmtSwitchDtuFreq(const uint32_t to_frequency);
|
||||
|
||||
CountryModeId_t _countryMode;
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -12,7 +12,8 @@ Command structure:
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
-----------------------------------------------------------------------------------------------------------------
|
||||
56 71 60 35 46 80 12 23 04 02 15 21 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
56 71 60 35 46 80 12 23 04 02 15 21 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (860 MHz band)
|
||||
56 71 60 35 46 80 12 23 04 03 17 3c 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (900 MHz band)
|
||||
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^
|
||||
ID Target Addr Source Addr ? ? ? CH ? CRC8
|
||||
*/
|
||||
@ -22,12 +23,10 @@ ChannelChangeCommand::ChannelChangeCommand(const uint64_t target_address, const
|
||||
: CommandAbstract(target_address, router_address)
|
||||
{
|
||||
_payload[0] = 0x56;
|
||||
_payload[9] = 0x02;
|
||||
_payload[10] = 0x15;
|
||||
_payload[11] = 0x21;
|
||||
_payload[13] = 0x14;
|
||||
_payload_size = 14;
|
||||
|
||||
setCountryMode(CountryModeId_t::MODE_EU);
|
||||
setChannel(channel);
|
||||
setTimeout(10);
|
||||
}
|
||||
@ -47,6 +46,27 @@ uint8_t ChannelChangeCommand::getChannel() const
|
||||
return _payload[12];
|
||||
}
|
||||
|
||||
void ChannelChangeCommand::setCountryMode(const CountryModeId_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case CountryModeId_t::MODE_US:
|
||||
_payload[9] = 0x03;
|
||||
_payload[10] = 0x17;
|
||||
_payload[11] = 0x3c;
|
||||
break;
|
||||
case CountryModeId_t::MODE_BR:
|
||||
_payload[9] = 0x03;
|
||||
_payload[10] = 0x17;
|
||||
_payload[11] = 0x3c;
|
||||
break;
|
||||
default:
|
||||
_payload[9] = 0x02;
|
||||
_payload[10] = 0x15;
|
||||
_payload[11] = 0x21;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelChangeCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id)
|
||||
{
|
||||
return true;
|
||||
@ -56,4 +76,4 @@ uint8_t ChannelChangeCommand::getMaxResendCount()
|
||||
{
|
||||
// This command will never retrieve an answer. Therefor it's not required to repeat it
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CommandAbstract.h"
|
||||
#include "../HoymilesRadio_CMT.h"
|
||||
|
||||
class ChannelChangeCommand : public CommandAbstract {
|
||||
public:
|
||||
@ -12,7 +13,9 @@ public:
|
||||
void setChannel(const uint8_t channel);
|
||||
uint8_t getChannel() const;
|
||||
|
||||
void setCountryMode(const CountryModeId_t mode);
|
||||
|
||||
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id);
|
||||
|
||||
virtual uint8_t getMaxResendCount();
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_1CH.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_1CH::HMS_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -51,4 +51,4 @@ const byteAssign_t* HMS_1CH::getByteAssignment() const
|
||||
uint8_t HMS_1CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_1CHv2.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 18, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_1CHv2::HMS_1CHv2(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -51,4 +51,4 @@ const byteAssign_t* HMS_1CHv2::getByteAssignment() const
|
||||
uint8_t HMS_1CHv2::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_2CH.h"
|
||||
|
||||
@ -10,14 +10,14 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 4, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 8, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -29,10 +29,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_2CH::HMS_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -58,4 +58,4 @@ const byteAssign_t* HMS_2CH::getByteAssignment() const
|
||||
uint8_t HMS_2CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 4, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 8, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 30, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 34, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 46, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 28, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 32, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 36, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 48, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 42, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 50, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 58, 2, 100, false, 2 },
|
||||
@ -43,10 +43,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 62, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 64, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_4CH::HMS_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -72,4 +72,4 @@ const byteAssign_t* HMS_4CH::getByteAssignment() const
|
||||
uint8_t HMS_4CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_Abstract.h"
|
||||
#include "Hoymiles.h"
|
||||
@ -19,7 +19,8 @@ bool HMS_Abstract::sendChangeChannelRequest()
|
||||
}
|
||||
|
||||
auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>();
|
||||
cmdChannel->setChannel(HoymilesRadio_CMT::getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
|
||||
cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode());
|
||||
cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
|
||||
cmdChannel->setTargetAddress(serial());
|
||||
_radio->enqueCommand(cmdChannel);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMT_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 74, 2, 10, false, 1 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_UAC_1N, UNIT_V, 68, 2, 10, false, 1 },
|
||||
@ -52,10 +52,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 94, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 96, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMT_4CH::HMT_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMT_6CH.h"
|
||||
|
||||
@ -10,42 +10,42 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH4, FLD_UDC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH4, FLD_IDC, UNIT_A, 48, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH4, FLD_PDC, UNIT_W, 52, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH4, FLD_YT, UNIT_KWH, 56, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH4, FLD_YD, UNIT_WH, 64, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH4, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH4, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH4, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH4, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH5, FLD_UDC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH5, FLD_IDC, UNIT_A, 50, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH5, FLD_PDC, UNIT_W, 54, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH5, FLD_YT, UNIT_KWH, 60, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH5, FLD_YD, UNIT_WH, 66, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH5, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH5, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH5, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH5, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 74, 2, 10, false, 1 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_UAC_1N, UNIT_V, 68, 2, 10, false, 1 },
|
||||
@ -57,7 +57,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_AC, CH0, FLD_F, UNIT_HZ, 80, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PAC, UNIT_W, 82, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_Q, UNIT_VAR, 84, 2, 10, true, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 86, 2, 100, false, 2 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, CALC_TOTAL_IAC, 0, CMD_CALC, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_1, UNIT_A, 86, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_2, UNIT_A, 88, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_3, UNIT_A, 90, 2, 100, false, 2 },
|
||||
@ -66,10 +66,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 94, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 96, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMT_6CH::HMT_6CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMT_Abstract.h"
|
||||
#include "Hoymiles.h"
|
||||
@ -21,9 +21,10 @@ bool HMT_Abstract::sendChangeChannelRequest()
|
||||
}
|
||||
|
||||
auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>();
|
||||
cmdChannel->setChannel(HoymilesRadio_CMT::getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
|
||||
cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode());
|
||||
cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
|
||||
cmdChannel->setTargetAddress(serial());
|
||||
_radio->enqueCommand(cmdChannel);
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HM_1CH.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_1CH::HM_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -64,4 +64,4 @@ const byteAssign_t* HM_1CH::getByteAssignment() const
|
||||
uint8_t HM_1CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HM_2CH.h"
|
||||
|
||||
@ -11,14 +11,14 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 10, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -30,10 +30,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_2CH::HM_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -72,4 +72,4 @@ const byteAssign_t* HM_2CH::getByteAssignment() const
|
||||
uint8_t HM_2CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HM_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, CALC_UDC_CH, CH0, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, CALC_CH_UDC, CH0, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, CALC_UDC_CH, CH2, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, CALC_CH_UDC, CH2, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 54, 2, 100, false, 2 },
|
||||
@ -43,10 +43,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 58, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 60, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_4CH::HM_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
@ -85,4 +85,4 @@ const byteAssign_t* HM_4CH::getByteAssignment() const
|
||||
uint8_t HM_4CH::getByteAssignmentSize() const
|
||||
{
|
||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,9 +28,11 @@ const devInfo_t devInfo[] = {
|
||||
{ { 0x10, 0x12, 0x30, ALL }, 1500, "HM-1500-4T" },
|
||||
{ { 0x10, 0x10, 0x10, 0x15 }, static_cast<uint16_t>(300 * 0.7), "HM-300-1T" }, // HM-300 factory limitted to 70%
|
||||
|
||||
{ { 0x10, 0x20, 0x11, ALL }, 300, "HMS-300-1T" }, // 00
|
||||
{ { 0x10, 0x20, 0x21, ALL }, 350, "HMS-350-1T" }, // 00
|
||||
{ { 0x10, 0x20, 0x41, ALL }, 400, "HMS-400-1T" }, // 00
|
||||
{ { 0x10, 0x10, 0x51, ALL }, 450, "HMS-450-1T" }, // 01
|
||||
{ { 0x10, 0x20, 0x51, ALL }, 450, "HMS-450-1T" }, // 03
|
||||
{ { 0x10, 0x10, 0x71, ALL }, 500, "HMS-500-1T" }, // 02
|
||||
{ { 0x10, 0x20, 0x71, ALL }, 500, "HMS-500-1T v2" }, // 02
|
||||
{ { 0x10, 0x21, 0x11, ALL }, 600, "HMS-600-2T" }, // 01
|
||||
@ -47,6 +49,7 @@ const devInfo_t devInfo[] = {
|
||||
|
||||
{ { 0x10, 0x32, 0x41, ALL }, 1600, "HMT-1600-4T" }, // 00
|
||||
{ { 0x10, 0x32, 0x51, ALL }, 1800, "HMT-1800-4T" }, // 00
|
||||
{ { 0x10, 0x32, 0x71, ALL }, 2000, "HMT-2000-4T" }, // 0
|
||||
|
||||
{ { 0x10, 0x33, 0x11, ALL }, 1800, "HMT-1800-6T" }, // 01
|
||||
{ { 0x10, 0x33, 0x31, ALL }, 2250, "HMT-2250-6T" } // 01
|
||||
@ -137,6 +140,14 @@ time_t DevInfoParser::getFwBuildDateTime() const
|
||||
return timegm(&timeinfo);
|
||||
}
|
||||
|
||||
String DevInfoParser::getFwBuildDateTimeStr() const
|
||||
{
|
||||
char timebuffer[32];
|
||||
const time_t t = getFwBuildDateTime();
|
||||
std::strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", gmtime(&t));
|
||||
return timebuffer;
|
||||
}
|
||||
|
||||
uint16_t DevInfoParser::getFwBootloaderVersion() const
|
||||
{
|
||||
HOY_SEMAPHORE_TAKE();
|
||||
@ -254,4 +265,4 @@ time_t DevInfoParser::timegm(const struct tm* t)
|
||||
result -= 3600;
|
||||
/*@ -matchanyintegral @*/
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ public:
|
||||
|
||||
uint16_t getFwBuildVersion() const;
|
||||
time_t getFwBuildDateTime() const;
|
||||
String getFwBuildDateTimeStr() const;
|
||||
uint16_t getFwBootloaderVersion() const;
|
||||
|
||||
uint32_t getHwPartNumber() const;
|
||||
@ -43,4 +44,4 @@ private:
|
||||
|
||||
uint8_t _payloadDevInfoSimple[DEV_INFO_SIZE] = {};
|
||||
uint8_t _devInfoSimpleLength = 0;
|
||||
};
|
||||
};
|
||||
|
||||
@ -390,7 +390,7 @@ std::vector<uint8_t> GridProfileParser::getRawData() const
|
||||
{
|
||||
std::vector<uint8_t> ret;
|
||||
HOY_SEMAPHORE_TAKE();
|
||||
for (uint8_t i = 0; i < GRID_PROFILE_SIZE; i++) {
|
||||
for (uint8_t i = 0; i < _gridProfileLength; i++) {
|
||||
ret.push_back(_payloadGridProfile[i]);
|
||||
}
|
||||
HOY_SEMAPHORE_GIVE();
|
||||
|
||||
@ -5,12 +5,13 @@
|
||||
#include "StatisticsParser.h"
|
||||
#include "../Hoymiles.h"
|
||||
|
||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcUdcCh(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcIrradiation(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalYieldTotal(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalYieldDay(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcChUdc(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalPowerDc(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalEffiency(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcChIrradiation(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalCurrentAc(StatisticsParser* iv, uint8_t arg0);
|
||||
|
||||
using func_t = float(StatisticsParser*, uint8_t);
|
||||
|
||||
@ -20,12 +21,13 @@ struct calcFunc_t {
|
||||
};
|
||||
|
||||
const calcFunc_t calcFunctions[] = {
|
||||
{ CALC_YT_CH0, &calcYieldTotalCh0 },
|
||||
{ CALC_YD_CH0, &calcYieldDayCh0 },
|
||||
{ CALC_UDC_CH, &calcUdcCh },
|
||||
{ CALC_PDC_CH0, &calcPowerDcCh0 },
|
||||
{ CALC_EFF_CH0, &calcEffiencyCh0 },
|
||||
{ CALC_IRR_CH, &calcIrradiation }
|
||||
{ CALC_TOTAL_YT, &calcTotalYieldTotal },
|
||||
{ CALC_TOTAL_YD, &calcTotalYieldDay },
|
||||
{ CALC_CH_UDC, &calcChUdc },
|
||||
{ CALC_TOTAL_PDC, &calcTotalPowerDc },
|
||||
{ CALC_TOTAL_EFF, &calcTotalEffiency },
|
||||
{ CALC_CH_IRR, &calcChIrradiation },
|
||||
{ CALC_TOTAL_IAC, &calcTotalCurrentAc }
|
||||
};
|
||||
|
||||
const FieldId_t runtimeFields[] = {
|
||||
@ -386,7 +388,7 @@ void StatisticsParser::resetYieldDayCorrection()
|
||||
}
|
||||
}
|
||||
|
||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalYieldTotal(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -395,7 +397,7 @@ static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
return yield;
|
||||
}
|
||||
|
||||
static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalYieldDay(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -405,12 +407,12 @@ static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
|
||||
// arg0 = channel of source
|
||||
static float calcUdcCh(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcChUdc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
return iv->getChannelFieldValue(TYPE_DC, static_cast<ChannelNum_t>(arg0), FLD_UDC);
|
||||
}
|
||||
|
||||
static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalPowerDc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float dcPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -419,8 +421,7 @@ static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
return dcPower;
|
||||
}
|
||||
|
||||
// arg0 = channel
|
||||
static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalEffiency(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float acPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_AC)) {
|
||||
@ -439,7 +440,7 @@ static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
|
||||
// arg0 = channel
|
||||
static float calcIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcChIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
if (nullptr != iv) {
|
||||
if (iv->getStringMaxPower(arg0) > 0)
|
||||
@ -447,3 +448,12 @@ static float calcIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static float calcTotalCurrentAc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float acCurrent = 0;
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1);
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_2);
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_3);
|
||||
return acCurrent;
|
||||
}
|
||||
|
||||
@ -55,12 +55,13 @@ const char* const fields[] = { "Voltage", "Current", "Power", "YieldDay", "Yield
|
||||
|
||||
// indices to calculation functions, defined in hmInverter.h
|
||||
enum {
|
||||
CALC_YT_CH0 = 0,
|
||||
CALC_YD_CH0,
|
||||
CALC_UDC_CH,
|
||||
CALC_PDC_CH0,
|
||||
CALC_EFF_CH0,
|
||||
CALC_IRR_CH
|
||||
CALC_TOTAL_YT = 0,
|
||||
CALC_TOTAL_YD,
|
||||
CALC_CH_UDC,
|
||||
CALC_TOTAL_PDC,
|
||||
CALC_TOTAL_EFF,
|
||||
CALC_CH_IRR,
|
||||
CALC_TOTAL_IAC
|
||||
};
|
||||
enum { CMD_CALC = 0xffff };
|
||||
|
||||
@ -169,4 +170,4 @@ private:
|
||||
|
||||
bool _enableYieldDayCorrection = false;
|
||||
float _lastYieldDay[CH_CNT] = {};
|
||||
};
|
||||
};
|
||||
|
||||
6
partitions_custom_16mb.csv
Normal file
6
partitions_custom_16mb.csv
Normal file
@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000
|
||||
otadata, data, ota, 0xE000, 0x2000
|
||||
app0, app, ota_0, 0x10000, 0x7E0000
|
||||
app1, app, ota_1, 0x7F0000, 0x7E0000
|
||||
spiffs, data, spiffs, 0xFD0000, 0x30000
|
||||
|
@ -9,7 +9,10 @@ import re
|
||||
Import("env")
|
||||
|
||||
def getPatchPath(env):
|
||||
return os.path.join(env["PROJECT_DIR"], "patches", env.GetProjectOption('custom_patches'))
|
||||
patchList = []
|
||||
for patch in env.GetProjectOption('custom_patches').split(","):
|
||||
patchList.append(os.path.join(env["PROJECT_DIR"], "patches", patch))
|
||||
return patchList
|
||||
|
||||
def is_tool(name):
|
||||
"""Check whether `name` is on PATH and marked as executable."""
|
||||
@ -44,35 +47,36 @@ def main():
|
||||
print('Git not found. Will not apply custom patches!')
|
||||
return
|
||||
|
||||
directory = getPatchPath(env)
|
||||
if (not os.path.isdir(directory)):
|
||||
print('Patch directory not found: ' + directory)
|
||||
return
|
||||
directories = getPatchPath(env)
|
||||
for directory in directories:
|
||||
if (not os.path.isdir(directory)):
|
||||
print('Patch directory not found: ' + directory)
|
||||
return
|
||||
|
||||
for file in os.listdir(directory):
|
||||
if (not file.endswith('.patch')):
|
||||
continue
|
||||
for file in os.listdir(directory):
|
||||
if (not file.endswith('.patch')):
|
||||
continue
|
||||
|
||||
fullPath = os.path.join(directory, file)
|
||||
preparePath = fullPath + '.prepare'
|
||||
replaceInFile(fullPath, preparePath, '$$$env$$$', env['PIOENV'])
|
||||
print('Working on patch: ' + fullPath + '... ', end='')
|
||||
fullPath = os.path.join(directory, file)
|
||||
preparePath = fullPath + '.prepare'
|
||||
replaceInFile(fullPath, preparePath, '$$$env$$$', env['PIOENV'])
|
||||
print('Working on patch: ' + fullPath + '... ', end='')
|
||||
|
||||
# Check if patch was already applied
|
||||
process = subprocess.run(['git', 'apply', '--reverse', '--check', preparePath], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if (process.returncode == 0):
|
||||
print('already applied')
|
||||
os.remove(preparePath)
|
||||
continue
|
||||
|
||||
# Apply patch
|
||||
process = subprocess.run(['git', 'apply', preparePath])
|
||||
if (process.returncode == 0):
|
||||
print('applied')
|
||||
else:
|
||||
print('failed')
|
||||
|
||||
# Check if patch was already applied
|
||||
process = subprocess.run(['git', 'apply', '--reverse', '--check', preparePath], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if (process.returncode == 0):
|
||||
print('already applied')
|
||||
os.remove(preparePath)
|
||||
continue
|
||||
|
||||
# Apply patch
|
||||
process = subprocess.run(['git', 'apply', preparePath])
|
||||
if (process.returncode == 0):
|
||||
print('applied')
|
||||
else:
|
||||
print('failed')
|
||||
|
||||
os.remove(preparePath)
|
||||
|
||||
|
||||
main()
|
||||
main()
|
||||
|
||||
486
platformio.ini
486
platformio.ini
@ -1,237 +1,249 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = generic_esp32
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
[env]
|
||||
; Make sure to NOT add any spaces in the custom_ci_action property
|
||||
; (also the position in the file is important)
|
||||
custom_ci_action = generic,generic_esp32,generic_esp32s3,generic_esp32s3_usb
|
||||
|
||||
framework = arduino
|
||||
platform = espressif32@6.5.0
|
||||
|
||||
build_flags =
|
||||
-DPIOENV=\"$PIOENV\"
|
||||
-D_TASK_STD_FUNCTION=1
|
||||
-D_TASK_THREAD_SAFE=1
|
||||
-Wall -Wextra -Wunused -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference
|
||||
; Have to remove -Werror because of
|
||||
; https://github.com/espressif/arduino-esp32/issues/9044 and
|
||||
; https://github.com/espressif/arduino-esp32/issues/9045
|
||||
; -Werror
|
||||
-std=c++17
|
||||
-std=gnu++17
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
|
||||
lib_deps =
|
||||
https://github.com/yubox-node-org/ESPAsyncWebServer
|
||||
bblanchon/ArduinoJson @ ^6.21.4
|
||||
https://github.com/bertmelis/espMqttClient.git#v1.5.0
|
||||
nrf24/RF24 @ ^1.4.8
|
||||
olikraus/U8g2 @ ^2.35.9
|
||||
buelowp/sunset @ ^1.1.7
|
||||
https://github.com/arkhipenko/TaskScheduler#testing
|
||||
|
||||
extra_scripts =
|
||||
pre:pio-scripts/auto_firmware_version.py
|
||||
pre:pio-scripts/patch_apply.py
|
||||
post:pio-scripts/create_factory_bin.py
|
||||
|
||||
board_build.partitions = partitions_custom.csv
|
||||
board_build.filesystem = littlefs
|
||||
board_build.embed_files =
|
||||
webapp_dist/index.html.gz
|
||||
webapp_dist/zones.json.gz
|
||||
webapp_dist/favicon.ico
|
||||
webapp_dist/favicon.png
|
||||
webapp_dist/js/app.js.gz
|
||||
webapp_dist/site.webmanifest
|
||||
|
||||
monitor_filters = esp32_exception_decoder, time, log2file, colorize
|
||||
monitor_speed = 115200
|
||||
upload_protocol = esptool
|
||||
|
||||
; Specify port in platformio_override.ini. Comment out (add ; in front of line) to use auto detection.
|
||||
; monitor_port = COM4
|
||||
; upload_port = COM4
|
||||
|
||||
|
||||
[env:generic_esp32]
|
||||
board = esp32dev
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32c3]
|
||||
board = esp32-c3-devkitc-02
|
||||
custom_patches = esp32c3
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32c3_usb]
|
||||
board = esp32-c3-devkitc-02
|
||||
custom_patches = esp32c3
|
||||
build_flags = ${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
|
||||
[env:generic_esp32s3]
|
||||
board = esp32-s3-devkitc-1
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32s3_usb]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
build_flags = ${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
|
||||
[env:generic]
|
||||
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]
|
||||
; https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware
|
||||
board = esp32-poe
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=15
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=14
|
||||
-DHOYMILES_PIN_IRQ=13
|
||||
-DHOYMILES_PIN_CE=16
|
||||
-DHOYMILES_PIN_CS=5
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[env:olimex_esp32_evb]
|
||||
; https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware
|
||||
board = esp32-evb
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=15
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=14
|
||||
-DHOYMILES_PIN_IRQ=13
|
||||
-DHOYMILES_PIN_CE=16
|
||||
-DHOYMILES_PIN_CS=17
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[env:d1_mini_esp32]
|
||||
board = wemos_d1_mini32
|
||||
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
|
||||
|
||||
|
||||
[env:wt32_eth01]
|
||||
; http://www.wireless-tag.com/portfolio/wt32-eth01/
|
||||
board = wt32-eth01
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=4
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=32
|
||||
-DHOYMILES_PIN_IRQ=33
|
||||
-DHOYMILES_PIN_CE=14
|
||||
-DHOYMILES_PIN_CS=15
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[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
|
||||
|
||||
[env:lolin_s2_mini]
|
||||
board = lolin_s2_mini
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=13
|
||||
-DHOYMILES_PIN_MOSI=11
|
||||
-DHOYMILES_PIN_SCLK=12
|
||||
-DHOYMILES_PIN_CS=10
|
||||
-DHOYMILES_PIN_IRQ=4
|
||||
-DHOYMILES_PIN_CE=5
|
||||
|
||||
|
||||
[env:opendtufusionv1]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
debug_tool = esp-builtin
|
||||
debug_speed = 12000
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=48
|
||||
-DHOYMILES_PIN_MOSI=35
|
||||
-DHOYMILES_PIN_SCLK=36
|
||||
-DHOYMILES_PIN_IRQ=47
|
||||
-DHOYMILES_PIN_CE=38
|
||||
-DHOYMILES_PIN_CS=37
|
||||
-DLED0=17
|
||||
-DLED1=18
|
||||
-DARDUINO_USB_MODE=1
|
||||
|
||||
[env:opendtufusionv2]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
debug_tool = esp-builtin
|
||||
debug_speed = 12000
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=48
|
||||
-DHOYMILES_PIN_MOSI=35
|
||||
-DHOYMILES_PIN_SCLK=36
|
||||
-DHOYMILES_PIN_IRQ=47
|
||||
-DHOYMILES_PIN_CE=38
|
||||
-DHOYMILES_PIN_CS=37
|
||||
-DLED0=17
|
||||
-DLED1=18
|
||||
-DCMT_CLK=6
|
||||
-DCMT_CS=4
|
||||
-DCMT_FCS=21
|
||||
-DCMT_GPIO2=3
|
||||
-DCMT_GPIO3=8
|
||||
-DCMT_SDIO=5
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = generic_esp32
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
[env]
|
||||
; Make sure to NOT add any spaces in the custom_ci_action property
|
||||
; (also the position in the file is important)
|
||||
custom_ci_action = generic,generic_esp32,generic_esp32s3,generic_esp32s3_usb
|
||||
|
||||
framework = arduino
|
||||
platform = espressif32@6.5.0
|
||||
|
||||
build_flags =
|
||||
-DPIOENV=\"$PIOENV\"
|
||||
-D_TASK_STD_FUNCTION=1
|
||||
-D_TASK_THREAD_SAFE=1
|
||||
-Wall -Wextra -Wunused -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference
|
||||
; Have to remove -Werror because of
|
||||
; https://github.com/espressif/arduino-esp32/issues/9044 and
|
||||
; https://github.com/espressif/arduino-esp32/issues/9045
|
||||
; -Werror
|
||||
-std=c++17
|
||||
-std=gnu++17
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
|
||||
lib_deps =
|
||||
mathieucarbou/ESP Async WebServer @ 2.7.0
|
||||
bblanchon/ArduinoJson @ ^6.21.5
|
||||
https://github.com/bertmelis/espMqttClient.git#v1.6.0
|
||||
nrf24/RF24 @ ^1.4.8
|
||||
olikraus/U8g2 @ ^2.35.9
|
||||
buelowp/sunset @ ^1.1.7
|
||||
https://github.com/arkhipenko/TaskScheduler#testing
|
||||
|
||||
extra_scripts =
|
||||
pre:pio-scripts/auto_firmware_version.py
|
||||
pre:pio-scripts/patch_apply.py
|
||||
post:pio-scripts/create_factory_bin.py
|
||||
|
||||
board_build.partitions = partitions_custom_4mb.csv
|
||||
board_build.filesystem = littlefs
|
||||
board_build.embed_files =
|
||||
webapp_dist/index.html.gz
|
||||
webapp_dist/zones.json.gz
|
||||
webapp_dist/favicon.ico
|
||||
webapp_dist/favicon.png
|
||||
webapp_dist/js/app.js.gz
|
||||
webapp_dist/site.webmanifest
|
||||
|
||||
custom_patches =
|
||||
|
||||
monitor_filters = esp32_exception_decoder, time, log2file, colorize
|
||||
monitor_speed = 115200
|
||||
upload_protocol = esptool
|
||||
|
||||
; Specify port in platformio_override.ini. Comment out (add ; in front of line) to use auto detection.
|
||||
; monitor_port = COM4
|
||||
; upload_port = COM4
|
||||
|
||||
|
||||
[env:generic_esp32]
|
||||
board = esp32dev
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32_16mb_psram]
|
||||
board = esp32dev
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = partitions_custom_16mb.csv
|
||||
board_upload.flash_size = 16MB
|
||||
build_flags = ${env.build_flags}
|
||||
-DBOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
|
||||
|
||||
[env:generic_esp32c3]
|
||||
board = esp32-c3-devkitc-02
|
||||
custom_patches = ${env.custom_patches},esp32c3
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32c3_usb]
|
||||
board = esp32-c3-devkitc-02
|
||||
custom_patches = ${env.custom_patches},esp32c3
|
||||
build_flags = ${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
|
||||
[env:generic_esp32s3]
|
||||
board = esp32-s3-devkitc-1
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32s3_usb]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
build_flags = ${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
|
||||
[env:generic]
|
||||
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]
|
||||
; https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware
|
||||
board = esp32-poe
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=15
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=14
|
||||
-DHOYMILES_PIN_IRQ=13
|
||||
-DHOYMILES_PIN_CE=16
|
||||
-DHOYMILES_PIN_CS=5
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[env:olimex_esp32_evb]
|
||||
; https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware
|
||||
board = esp32-evb
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=15
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=14
|
||||
-DHOYMILES_PIN_IRQ=13
|
||||
-DHOYMILES_PIN_CE=16
|
||||
-DHOYMILES_PIN_CS=17
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[env:d1_mini_esp32]
|
||||
board = wemos_d1_mini32
|
||||
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
|
||||
|
||||
|
||||
[env:wt32_eth01]
|
||||
; http://www.wireless-tag.com/portfolio/wt32-eth01/
|
||||
board = wt32-eth01
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=4
|
||||
-DHOYMILES_PIN_MOSI=2
|
||||
-DHOYMILES_PIN_SCLK=32
|
||||
-DHOYMILES_PIN_IRQ=33
|
||||
-DHOYMILES_PIN_CE=14
|
||||
-DHOYMILES_PIN_CS=15
|
||||
-DOPENDTU_ETHERNET
|
||||
|
||||
|
||||
[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
|
||||
|
||||
[env:lolin_s2_mini]
|
||||
board = lolin_s2_mini
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=13
|
||||
-DHOYMILES_PIN_MOSI=11
|
||||
-DHOYMILES_PIN_SCLK=12
|
||||
-DHOYMILES_PIN_CS=10
|
||||
-DHOYMILES_PIN_IRQ=4
|
||||
-DHOYMILES_PIN_CE=5
|
||||
|
||||
|
||||
[env:opendtufusionv1]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
debug_tool = esp-builtin
|
||||
debug_speed = 12000
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=48
|
||||
-DHOYMILES_PIN_MOSI=35
|
||||
-DHOYMILES_PIN_SCLK=36
|
||||
-DHOYMILES_PIN_IRQ=47
|
||||
-DHOYMILES_PIN_CE=38
|
||||
-DHOYMILES_PIN_CS=37
|
||||
-DLED0=17
|
||||
-DLED1=18
|
||||
-DARDUINO_USB_MODE=1
|
||||
|
||||
[env:opendtufusionv2]
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
debug_tool = esp-builtin
|
||||
debug_speed = 12000
|
||||
build_flags = ${env.build_flags}
|
||||
-DHOYMILES_PIN_MISO=48
|
||||
-DHOYMILES_PIN_MOSI=35
|
||||
-DHOYMILES_PIN_SCLK=36
|
||||
-DHOYMILES_PIN_IRQ=47
|
||||
-DHOYMILES_PIN_CE=38
|
||||
-DHOYMILES_PIN_CS=37
|
||||
-DLED0=17
|
||||
-DLED1=18
|
||||
-DCMT_CLK=6
|
||||
-DCMT_CS=4
|
||||
-DCMT_FCS=21
|
||||
-DCMT_GPIO2=3
|
||||
-DCMT_GPIO3=8
|
||||
-DCMT_SDIO=5
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "Configuration.h"
|
||||
#include "MessageOutput.h"
|
||||
@ -95,6 +95,7 @@ bool ConfigurationClass::write()
|
||||
dtu["nrf_pa_level"] = config.Dtu.Nrf.PaLevel;
|
||||
dtu["cmt_pa_level"] = config.Dtu.Cmt.PaLevel;
|
||||
dtu["cmt_frequency"] = config.Dtu.Cmt.Frequency;
|
||||
dtu["cmt_country_mode"] = config.Dtu.Cmt.CountryMode;
|
||||
|
||||
JsonObject security = doc.createNestedObject("security");
|
||||
security["password"] = config.Security.Password;
|
||||
@ -109,7 +110,8 @@ bool ConfigurationClass::write()
|
||||
display["rotation"] = config.Display.Rotation;
|
||||
display["contrast"] = config.Display.Contrast;
|
||||
display["language"] = config.Display.Language;
|
||||
display["diagram_duration"] = config.Display.DiagramDuration;
|
||||
display["diagram_duration"] = config.Display.Diagram.Duration;
|
||||
display["diagram_mode"] = config.Display.Diagram.Mode;
|
||||
|
||||
JsonArray leds = device.createNestedArray("led");
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
@ -262,6 +264,7 @@ bool ConfigurationClass::read()
|
||||
config.Dtu.Nrf.PaLevel = dtu["nrf_pa_level"] | DTU_NRF_PA_LEVEL;
|
||||
config.Dtu.Cmt.PaLevel = dtu["cmt_pa_level"] | DTU_CMT_PA_LEVEL;
|
||||
config.Dtu.Cmt.Frequency = dtu["cmt_frequency"] | DTU_CMT_FREQUENCY;
|
||||
config.Dtu.Cmt.CountryMode = dtu["cmt_country_mode"] | DTU_CMT_COUNTRY_MODE;
|
||||
|
||||
JsonObject security = doc["security"];
|
||||
strlcpy(config.Security.Password, security["password"] | ACCESS_POINT_PASSWORD, sizeof(config.Security.Password));
|
||||
@ -276,7 +279,8 @@ bool ConfigurationClass::read()
|
||||
config.Display.Rotation = display["rotation"] | DISPLAY_ROTATION;
|
||||
config.Display.Contrast = display["contrast"] | DISPLAY_CONTRAST;
|
||||
config.Display.Language = display["language"] | DISPLAY_LANGUAGE;
|
||||
config.Display.DiagramDuration = display["diagram_duration"] | DISPLAY_DIAGRAM_DURATION;
|
||||
config.Display.Diagram.Duration = display["diagram_duration"] | DISPLAY_DIAGRAM_DURATION;
|
||||
config.Display.Diagram.Mode = display["diagram_mode"] | DISPLAY_DIAGRAM_MODE;
|
||||
|
||||
JsonArray leds = device["led"];
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
@ -363,6 +367,11 @@ void ConfigurationClass::migrate()
|
||||
nvs_flash_init();
|
||||
}
|
||||
|
||||
if (config.Cfg.Version < 0x00011b00) {
|
||||
// Convert from kHz to Hz
|
||||
config.Dtu.Cmt.Frequency *= 1000;
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
config.Cfg.Version = CONFIG_VERSION;
|
||||
@ -397,4 +406,4 @@ INVERTER_CONFIG_T* ConfigurationClass::getInverterConfig(const uint64_t serial)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConfigurationClass Configuration;
|
||||
ConfigurationClass Configuration;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "Datastore.h"
|
||||
#include "Configuration.h"
|
||||
@ -8,12 +8,14 @@
|
||||
|
||||
DatastoreClass Datastore;
|
||||
|
||||
DatastoreClass::DatastoreClass()
|
||||
: _loopTask(1 * TASK_SECOND, TASK_FOREVER, std::bind(&DatastoreClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void DatastoreClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&DatastoreClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(1 * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
@ -79,14 +81,17 @@ void DatastoreClass::loop()
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_INV)) {
|
||||
if (cfg->Poll_Enable) {
|
||||
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_INV, c, FLD_YT);
|
||||
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_INV, c, FLD_YD);
|
||||
|
||||
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
||||
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
||||
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_INV, c, FLD_YT));
|
||||
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_INV, c, FLD_YD));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
if (inv->getEnablePolling()) {
|
||||
_totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
_totalAcPowerDigits = max<unsigned int>(_totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "Display_Graphic.h"
|
||||
#include "Datastore.h"
|
||||
@ -13,6 +13,7 @@ std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>
|
||||
{ DisplayType_t::SSD1306, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||
{ DisplayType_t::SH1106, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SH1106_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||
{ DisplayType_t::SSD1309, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1309_128X64_NONAME0_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||
{ DisplayType_t::ST7567_GM12864I_59N, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_ST7567_ENH_DG128064I_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||
};
|
||||
|
||||
// Language defintion, respect order in languages[] and translation lists
|
||||
@ -28,13 +29,15 @@ const uint8_t languages[] = {
|
||||
};
|
||||
|
||||
static const char* const i18n_offline[] = { "Offline", "Offline", "Offline" };
|
||||
static const char* const i18n_current_power_w[] = { "%3.0f W", "%3.0f W", "%3.0f W" };
|
||||
static const char* const i18n_current_power_kw[] = { "%2.1f kW", "%2.1f kW", "%2.1f kW" };
|
||||
static const char* const i18n_current_power_w[] = { "%.0f W", "%.0f W", "%.0f W" };
|
||||
static const char* const i18n_current_power_kw[] = { "%.1f kW", "%.1f kW", "%.1f kW" };
|
||||
static const char* const i18n_yield_today_wh[] = { "today: %4.0f Wh", "Heute: %4.0f Wh", "auj.: %4.0f Wh" };
|
||||
static const char* const i18n_yield_total_kwh[] = { "total: %.1f kWh", "Ges.: %.1f kWh", "total: %.1f kWh" };
|
||||
static const char* const i18n_yield_total_mwh[] = { "total: %.0f kWh", "Ges.: %.0f kWh", "total: %.0f kWh" };
|
||||
static const char* const i18n_date_format[] = { "%m/%d/%Y %H:%M", "%d.%m.%Y %H:%M", "%d/%m/%Y %H:%M" };
|
||||
|
||||
DisplayGraphicClass::DisplayGraphicClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&DisplayGraphicClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
@ -49,14 +52,15 @@ void DisplayGraphicClass::init(Scheduler& scheduler, const DisplayType_t type, c
|
||||
if (isValidDisplay()) {
|
||||
auto constructor = display_types[_display_type];
|
||||
_display = constructor(reset, clk, data, cs);
|
||||
if (_display_type == DisplayType_t::ST7567_GM12864I_59N) {
|
||||
_display->setI2CAddress(0x3F << 1);
|
||||
}
|
||||
_display->begin();
|
||||
setContrast(DISPLAY_CONTRAST);
|
||||
setStatus(true);
|
||||
_diagram.init(scheduler, _display);
|
||||
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&DisplayGraphicClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(_period);
|
||||
_loopTask.enable();
|
||||
}
|
||||
@ -64,11 +68,19 @@ void DisplayGraphicClass::init(Scheduler& scheduler, const DisplayType_t type, c
|
||||
|
||||
void DisplayGraphicClass::calcLineHeights()
|
||||
{
|
||||
uint8_t yOff = 0;
|
||||
bool diagram = (_isLarge && _diagram_mode == DiagramMode_t::Small);
|
||||
// the diagram needs space. we need to keep
|
||||
// away from the y-axis label in particular.
|
||||
uint8_t yOff = (diagram ? 7 : 0);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
setFont(i);
|
||||
yOff += (_display->getMaxCharHeight());
|
||||
yOff += _display->getAscent();
|
||||
_lineOffsets[i] = yOff;
|
||||
yOff += ((!_isLarge || diagram) ? 2 : 3);
|
||||
// the descent is a negative value and moves the *next* line's
|
||||
// baseline. the first line never uses a letter with descent and
|
||||
// we need that space when showing the small diagram.
|
||||
yOff -= ((i == 0 && diagram) ? 0 : _display->getDescent());
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,15 +106,29 @@ bool DisplayGraphicClass::isValidDisplay()
|
||||
|
||||
void DisplayGraphicClass::printText(const char* text, const uint8_t line)
|
||||
{
|
||||
setFont(line);
|
||||
|
||||
uint8_t dispX;
|
||||
if (!_isLarge) {
|
||||
dispX = (line == 0) ? 5 : 0;
|
||||
} else {
|
||||
dispX = (line == 0) ? 10 : 5;
|
||||
if (line == 0 && _diagram_mode == DiagramMode_t::Small) {
|
||||
// Center between left border and diagram
|
||||
dispX = (CHART_POSX - _display->getStrWidth(text)) / 2;
|
||||
} else {
|
||||
// Center on screen
|
||||
dispX = (_display->getDisplayWidth() - _display->getStrWidth(text)) / 2;
|
||||
}
|
||||
}
|
||||
setFont(line);
|
||||
|
||||
dispX += enableScreensaver ? (_mExtra % 7) : 0;
|
||||
if (enableScreensaver) {
|
||||
unsigned maxOffset = (_isLarge ? 8 : 6);
|
||||
unsigned period = 2 * maxOffset;
|
||||
unsigned step = _mExtra % period;
|
||||
int offset = (step <= maxOffset) ? step : (period - step);
|
||||
offset -= (_isLarge ? 5 : 0); // oscillate around center on large screens
|
||||
dispX += offset;
|
||||
}
|
||||
_display->drawStr(dispX, _lineOffsets[line], text);
|
||||
}
|
||||
|
||||
@ -136,6 +162,13 @@ void DisplayGraphicClass::setLanguage(const uint8_t language)
|
||||
_display_language = language < sizeof(languages) / sizeof(languages[0]) ? language : DISPLAY_LANGUAGE;
|
||||
}
|
||||
|
||||
void DisplayGraphicClass::setDiagramMode(DiagramMode_t mode)
|
||||
{
|
||||
if (mode < DiagramMode_t::DisplayMode_Max) {
|
||||
_diagram_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayGraphicClass::setStartupDisplay()
|
||||
{
|
||||
if (!isValidDisplay()) {
|
||||
@ -158,21 +191,37 @@ void DisplayGraphicClass::loop()
|
||||
|
||||
_display->clearBuffer();
|
||||
bool displayPowerSave = false;
|
||||
bool showText = true;
|
||||
|
||||
//=====> Actual Production ==========
|
||||
if (Datastore.getIsAtLeastOneReachable()) {
|
||||
displayPowerSave = false;
|
||||
if (_isLarge) {
|
||||
uint8_t screenSaverOffsetX = enableScreensaver ? (_mExtra % 7) : 0;
|
||||
_diagram.redraw(screenSaverOffsetX);
|
||||
switch (_diagram_mode) {
|
||||
case DiagramMode_t::Small:
|
||||
_diagram.redraw(screenSaverOffsetX, CHART_POSX, CHART_POSY, CHART_WIDTH, CHART_HEIGHT, false);
|
||||
break;
|
||||
case DiagramMode_t::Fullscreen:
|
||||
// Every 10 seconds
|
||||
if (_mExtra % (10 * 2) < 10) {
|
||||
_diagram.redraw(screenSaverOffsetX, 10, 0, _display->getDisplayWidth() - 12, _display->getDisplayHeight() - 3, true);
|
||||
showText = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
const float watts = Datastore.getTotalAcPowerEnabled();
|
||||
if (watts > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], watts / 1000);
|
||||
} else {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], watts);
|
||||
if (showText) {
|
||||
const float watts = Datastore.getTotalAcPowerEnabled();
|
||||
if (watts > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], watts / 1000);
|
||||
} else {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], watts);
|
||||
}
|
||||
printText(_fmtText, 0);
|
||||
}
|
||||
printText(_fmtText, 0);
|
||||
_previousMillis = millis();
|
||||
}
|
||||
//<=======================
|
||||
@ -187,23 +236,29 @@ void DisplayGraphicClass::loop()
|
||||
}
|
||||
//<=======================
|
||||
|
||||
//=====> Today & Total Production =======
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.getTotalAcYieldDayEnabled());
|
||||
printText(_fmtText, 1);
|
||||
if (showText) {
|
||||
//=====> Today & Total Production =======
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.getTotalAcYieldDayEnabled());
|
||||
printText(_fmtText, 1);
|
||||
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.getTotalAcYieldTotalEnabled());
|
||||
printText(_fmtText, 2);
|
||||
//<=======================
|
||||
const float watts = Datastore.getTotalAcYieldTotalEnabled();
|
||||
auto const format = (watts >= 1000) ? i18n_yield_total_mwh : i18n_yield_total_kwh;
|
||||
snprintf(_fmtText, sizeof(_fmtText), format[_display_language], watts);
|
||||
printText(_fmtText, 2);
|
||||
//<=======================
|
||||
|
||||
//=====> IP or Date-Time ========
|
||||
if (!(_mExtra % 10) && NetworkSettings.localIP()) {
|
||||
printText(NetworkSettings.localIP().toString().c_str(), 3);
|
||||
} else {
|
||||
// Get current time
|
||||
time_t now = time(nullptr);
|
||||
strftime(_fmtText, sizeof(_fmtText), i18n_date_format[_display_language], localtime(&now));
|
||||
printText(_fmtText, 3);
|
||||
//=====> IP or Date-Time ========
|
||||
// Change every 3 seconds
|
||||
if (!(_mExtra % (3 * 2) < 3) && NetworkSettings.localIP()) {
|
||||
printText(NetworkSettings.localIP().toString().c_str(), 3);
|
||||
} else {
|
||||
// Get current time
|
||||
time_t now = time(nullptr);
|
||||
strftime(_fmtText, sizeof(_fmtText), i18n_date_format[_display_language], localtime(&now));
|
||||
printText(_fmtText, 3);
|
||||
}
|
||||
}
|
||||
|
||||
_display->sendBuffer();
|
||||
|
||||
_mExtra++;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "Display_Graphic_Diagram.h"
|
||||
#include "Configuration.h"
|
||||
@ -8,6 +8,8 @@
|
||||
#include <algorithm>
|
||||
|
||||
DisplayGraphicDiagramClass::DisplayGraphicDiagramClass()
|
||||
: _averageTask(1 * TASK_SECOND, TASK_FOREVER, std::bind(&DisplayGraphicDiagramClass::averageLoop, this))
|
||||
, _dataPointTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&DisplayGraphicDiagramClass::dataPointLoop, this))
|
||||
{
|
||||
}
|
||||
|
||||
@ -16,14 +18,9 @@ void DisplayGraphicDiagramClass::init(Scheduler& scheduler, U8G2* display)
|
||||
_display = display;
|
||||
|
||||
scheduler.addTask(_averageTask);
|
||||
_averageTask.setCallback(std::bind(&DisplayGraphicDiagramClass::averageLoop, this));
|
||||
_averageTask.setIterations(TASK_FOREVER);
|
||||
_averageTask.setInterval(1 * TASK_SECOND);
|
||||
_averageTask.enable();
|
||||
|
||||
scheduler.addTask(_dataPointTask);
|
||||
_dataPointTask.setCallback(std::bind(&DisplayGraphicDiagramClass::dataPointLoop, this));
|
||||
_dataPointTask.setIterations(TASK_FOREVER);
|
||||
updatePeriod();
|
||||
_dataPointTask.enable();
|
||||
}
|
||||
@ -52,38 +49,39 @@ void DisplayGraphicDiagramClass::dataPointLoop()
|
||||
|
||||
uint32_t DisplayGraphicDiagramClass::getSecondsPerDot()
|
||||
{
|
||||
return Configuration.get().Display.DiagramDuration / CHART_WIDTH;
|
||||
return Configuration.get().Display.Diagram.Duration / _chartWidth;
|
||||
}
|
||||
|
||||
void DisplayGraphicDiagramClass::updatePeriod()
|
||||
{
|
||||
_dataPointTask.setInterval(getSecondsPerDot() * TASK_SECOND);
|
||||
// Calculate seconds per datapoint
|
||||
_dataPointTask.setInterval(Configuration.get().Display.Diagram.Duration * TASK_SECOND / MAX_DATAPOINTS);
|
||||
}
|
||||
|
||||
void DisplayGraphicDiagramClass::redraw(uint8_t screenSaverOffsetX)
|
||||
void DisplayGraphicDiagramClass::redraw(uint8_t screenSaverOffsetX, uint8_t xPos, uint8_t yPos, uint8_t width, uint8_t height, bool isFullscreen)
|
||||
{
|
||||
// screenSaverOffsetX expected to be in range 0..6
|
||||
const uint8_t graphPosX = DIAG_POSX + ((screenSaverOffsetX > 3) ? 1 : 0);
|
||||
const uint8_t graphPosY = DIAG_POSY + ((screenSaverOffsetX > 3) ? 1 : 0);
|
||||
_chartWidth = width;
|
||||
|
||||
const uint8_t horizontal_line_y = graphPosY + CHART_HEIGHT - 1;
|
||||
// screenSaverOffsetX expected to be in range 0..6
|
||||
const uint8_t graphPosX = xPos + ((screenSaverOffsetX > 3) ? 1 : 0);
|
||||
const uint8_t graphPosY = yPos + ((screenSaverOffsetX > 3) ? 1 : 0);
|
||||
|
||||
const uint8_t horizontal_line_y = graphPosY + height - 1;
|
||||
const uint8_t arrow_size = 2;
|
||||
|
||||
// draw diagram axis
|
||||
_display->drawVLine(graphPosX, graphPosY, CHART_HEIGHT);
|
||||
_display->drawHLine(graphPosX, horizontal_line_y, CHART_WIDTH);
|
||||
_display->drawVLine(graphPosX, graphPosY, height);
|
||||
_display->drawHLine(graphPosX, horizontal_line_y, width);
|
||||
|
||||
// UP-arrow
|
||||
_display->drawLine(graphPosX, graphPosY, graphPosX + arrow_size, graphPosY + arrow_size);
|
||||
_display->drawLine(graphPosX, graphPosY, graphPosX - arrow_size, graphPosY + arrow_size);
|
||||
|
||||
// LEFT-arrow
|
||||
_display->drawLine(graphPosX + CHART_WIDTH - 1, horizontal_line_y, graphPosX + CHART_WIDTH - 1 - arrow_size, horizontal_line_y - arrow_size);
|
||||
_display->drawLine(graphPosX + CHART_WIDTH - 1, horizontal_line_y, graphPosX + CHART_WIDTH - 1 - arrow_size, horizontal_line_y + arrow_size);
|
||||
_display->drawLine(graphPosX + width - 1, horizontal_line_y, graphPosX + width - 1 - arrow_size, horizontal_line_y - arrow_size);
|
||||
_display->drawLine(graphPosX + width - 1, horizontal_line_y, graphPosX + width - 1 - arrow_size, horizontal_line_y + arrow_size);
|
||||
|
||||
// draw AC value
|
||||
// 4 pixels per char
|
||||
_display->setFont(u8g2_font_tom_thumb_4x6_mr);
|
||||
char fmtText[7];
|
||||
const float maxWatts = *std::max_element(_graphValues.begin(), _graphValues.end());
|
||||
if (maxWatts > 999) {
|
||||
@ -91,25 +89,48 @@ void DisplayGraphicDiagramClass::redraw(uint8_t screenSaverOffsetX)
|
||||
} else {
|
||||
snprintf(fmtText, sizeof(fmtText), "%dW", static_cast<uint16_t>(maxWatts));
|
||||
}
|
||||
const uint8_t textLength = strlen(fmtText);
|
||||
_display->drawStr(graphPosX - arrow_size - textLength * 4, graphPosY + 5, fmtText);
|
||||
|
||||
if (isFullscreen) {
|
||||
_display->setFont(u8g2_font_5x8_tr);
|
||||
_display->setFontDirection(3);
|
||||
_display->drawStr(graphPosX - arrow_size, graphPosY + _display->getStrWidth(fmtText), fmtText);
|
||||
_display->setFontDirection(0);
|
||||
} else {
|
||||
// 4 pixels per char
|
||||
_display->setFont(u8g2_font_tom_thumb_4x6_mr);
|
||||
_display->drawStr(graphPosX - arrow_size - _display->getStrWidth(fmtText), graphPosY + 5, fmtText);
|
||||
}
|
||||
|
||||
// draw chart
|
||||
const float scaleFactor = maxWatts / CHART_HEIGHT;
|
||||
uint8_t axisTick = 1;
|
||||
const float scaleFactorY = maxWatts / static_cast<float>(height);
|
||||
const float scaleFactorX = static_cast<float>(MAX_DATAPOINTS) / static_cast<float>(_chartWidth);
|
||||
|
||||
if (maxWatts > 0 && isFullscreen) {
|
||||
// draw y axis ticks
|
||||
const uint16_t yAxisWattPerTick = maxWatts <= 100 ? 10 : maxWatts <= 1000 ? 100
|
||||
: maxWatts < 5000 ? 500
|
||||
: 1000;
|
||||
const uint8_t yAxisTickSizePixel = height / (maxWatts / yAxisWattPerTick);
|
||||
|
||||
for (int16_t tickYPos = graphPosY + height; tickYPos > graphPosY - arrow_size; tickYPos -= yAxisTickSizePixel) {
|
||||
_display->drawPixel(graphPosX - 1, tickYPos);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t xAxisTicks = 1;
|
||||
for (uint8_t i = 1; i < _graphValuesCount; i++) {
|
||||
// draw one tick per hour to the x-axis
|
||||
if (i * getSecondsPerDot() > (3600u * axisTick)) {
|
||||
_display->drawPixel(graphPosX + 1 + i, graphPosY + CHART_HEIGHT);
|
||||
axisTick++;
|
||||
if (i * getSecondsPerDot() > (3600u * xAxisTicks)) {
|
||||
_display->drawPixel((graphPosX + 1 + i) * scaleFactorX, graphPosY + height);
|
||||
xAxisTicks++;
|
||||
}
|
||||
|
||||
if (scaleFactor == 0) {
|
||||
if (scaleFactorY == 0 || scaleFactorX == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_display->drawLine(
|
||||
graphPosX + i - 1, horizontal_line_y - std::max<int16_t>(0, _graphValues[i - 1] / scaleFactor - 0.5),
|
||||
graphPosX + i, horizontal_line_y - std::max<int16_t>(0, _graphValues[i] / scaleFactor - 0.5));
|
||||
graphPosX + (i - 1) / scaleFactorX, horizontal_line_y - std::max<int16_t>(0, _graphValues[i - 1] / scaleFactorY - 0.5),
|
||||
graphPosX + i / scaleFactorX, horizontal_line_y - std::max<int16_t>(0, _graphValues[i] / scaleFactorY - 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "InverterSettings.h"
|
||||
#include "Configuration.h"
|
||||
@ -25,6 +25,12 @@
|
||||
|
||||
InverterSettingsClass InverterSettings;
|
||||
|
||||
InverterSettingsClass::InverterSettingsClass()
|
||||
: _settingsTask(INVERTER_UPDATE_SETTINGS_INTERVAL, TASK_FOREVER, std::bind(&InverterSettingsClass::settingsLoop, this))
|
||||
, _hoyTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&InverterSettingsClass::hoyLoop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void InverterSettingsClass::init(Scheduler& scheduler)
|
||||
{
|
||||
const CONFIG_T& config = Configuration.get();
|
||||
@ -45,6 +51,8 @@ void InverterSettingsClass::init(Scheduler& scheduler)
|
||||
|
||||
if (PinMapping.isValidCmt2300Config()) {
|
||||
Hoymiles.initCMT(pin.cmt_sdio, pin.cmt_clk, pin.cmt_cs, pin.cmt_fcs, pin.cmt_gpio2, pin.cmt_gpio3);
|
||||
MessageOutput.println(F(" Setting country mode... "));
|
||||
Hoymiles.getRadioCmt()->setCountryMode(static_cast<CountryModeId_t>(config.Dtu.Cmt.CountryMode));
|
||||
MessageOutput.println(F(" Setting CMT target frequency... "));
|
||||
Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency);
|
||||
}
|
||||
@ -89,20 +97,16 @@ void InverterSettingsClass::init(Scheduler& scheduler)
|
||||
}
|
||||
|
||||
scheduler.addTask(_hoyTask);
|
||||
_hoyTask.setCallback(std::bind(&InverterSettingsClass::hoyLoop, this));
|
||||
_hoyTask.setIterations(TASK_FOREVER);
|
||||
_hoyTask.enable();
|
||||
|
||||
scheduler.addTask(_settingsTask);
|
||||
_settingsTask.setCallback(std::bind(&InverterSettingsClass::settingsLoop, this));
|
||||
_settingsTask.setIterations(TASK_FOREVER);
|
||||
_settingsTask.setInterval(INVERTER_UPDATE_SETTINGS_INTERVAL);
|
||||
_settingsTask.enable();
|
||||
}
|
||||
|
||||
void InverterSettingsClass::settingsLoop()
|
||||
{
|
||||
const CONFIG_T& config = Configuration.get();
|
||||
const bool isDayPeriod = SunPosition.isDayPeriod();
|
||||
|
||||
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
||||
auto const& inv_cfg = config.Inverter[i];
|
||||
@ -114,10 +118,10 @@ void InverterSettingsClass::settingsLoop()
|
||||
continue;
|
||||
}
|
||||
|
||||
inv->setEnablePolling(inv_cfg.Poll_Enable && (SunPosition.isDayPeriod() || inv_cfg.Poll_Enable_Night));
|
||||
inv->setEnableCommands(inv_cfg.Command_Enable && (SunPosition.isDayPeriod() || inv_cfg.Command_Enable_Night));
|
||||
inv->setEnablePolling(inv_cfg.Poll_Enable && (isDayPeriod || inv_cfg.Poll_Enable_Night));
|
||||
inv->setEnableCommands(inv_cfg.Command_Enable && (isDayPeriod || inv_cfg.Command_Enable_Night));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InverterSettingsClass::hoyLoop()
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "Led_Single.h"
|
||||
#include "Configuration.h"
|
||||
@ -38,6 +38,8 @@ const uint8_t pwmTable[] = {
|
||||
#define LED_OFF 0
|
||||
|
||||
LedSingleClass::LedSingleClass()
|
||||
: _setTask(LEDSINGLE_UPDATE_INTERVAL * TASK_MILLISECOND, TASK_FOREVER, std::bind(&LedSingleClass::setLoop, this))
|
||||
, _outputTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&LedSingleClass::outputLoop, this))
|
||||
{
|
||||
}
|
||||
|
||||
@ -62,14 +64,9 @@ void LedSingleClass::init(Scheduler& scheduler)
|
||||
|
||||
if (ledActive) {
|
||||
scheduler.addTask(_outputTask);
|
||||
_outputTask.setCallback(std::bind(&LedSingleClass::outputLoop, this));
|
||||
_outputTask.setIterations(TASK_FOREVER);
|
||||
_outputTask.enable();
|
||||
|
||||
scheduler.addTask(_setTask);
|
||||
_setTask.setCallback(std::bind(&LedSingleClass::setLoop, this));
|
||||
_setTask.setInterval(LEDSINGLE_UPDATE_INTERVAL * TASK_MILLISECOND);
|
||||
_setTask.setIterations(TASK_FOREVER);
|
||||
_setTask.enable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,63 +1,66 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
*/
|
||||
#include "MessageOutput.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
MessageOutputClass MessageOutput;
|
||||
|
||||
void MessageOutputClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&MessageOutputClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
void MessageOutputClass::register_ws_output(AsyncWebSocket* output)
|
||||
{
|
||||
_ws = output;
|
||||
}
|
||||
|
||||
size_t MessageOutputClass::write(uint8_t c)
|
||||
{
|
||||
if (_buff_pos < BUFFER_SIZE) {
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
_buffer[_buff_pos] = c;
|
||||
_buff_pos++;
|
||||
} else {
|
||||
_forceSend = true;
|
||||
}
|
||||
|
||||
return Serial.write(c);
|
||||
}
|
||||
|
||||
size_t MessageOutputClass::write(const uint8_t* buffer, size_t size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
if (_buff_pos + size < BUFFER_SIZE) {
|
||||
memcpy(&_buffer[_buff_pos], buffer, size);
|
||||
_buff_pos += size;
|
||||
}
|
||||
_forceSend = true;
|
||||
|
||||
return Serial.write(buffer, size);
|
||||
}
|
||||
|
||||
void MessageOutputClass::loop()
|
||||
{
|
||||
// Send data via websocket if either time is over or buffer is full
|
||||
if (_forceSend || (millis() - _lastSend > 1000)) {
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
if (_ws && _buff_pos > 0) {
|
||||
_ws->textAll(_buffer, _buff_pos);
|
||||
_buff_pos = 0;
|
||||
}
|
||||
if (_forceSend) {
|
||||
_buff_pos = 0;
|
||||
}
|
||||
_forceSend = false;
|
||||
}
|
||||
}
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "MessageOutput.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
MessageOutputClass MessageOutput;
|
||||
|
||||
MessageOutputClass::MessageOutputClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&MessageOutputClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void MessageOutputClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
void MessageOutputClass::register_ws_output(AsyncWebSocket* output)
|
||||
{
|
||||
_ws = output;
|
||||
}
|
||||
|
||||
size_t MessageOutputClass::write(uint8_t c)
|
||||
{
|
||||
if (_buff_pos < BUFFER_SIZE) {
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
_buffer[_buff_pos] = c;
|
||||
_buff_pos++;
|
||||
} else {
|
||||
_forceSend = true;
|
||||
}
|
||||
|
||||
return Serial.write(c);
|
||||
}
|
||||
|
||||
size_t MessageOutputClass::write(const uint8_t* buffer, size_t size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
if (_buff_pos + size < BUFFER_SIZE) {
|
||||
memcpy(&_buffer[_buff_pos], buffer, size);
|
||||
_buff_pos += size;
|
||||
}
|
||||
_forceSend = true;
|
||||
|
||||
return Serial.write(buffer, size);
|
||||
}
|
||||
|
||||
void MessageOutputClass::loop()
|
||||
{
|
||||
// Send data via websocket if either time is over or buffer is full
|
||||
if (_forceSend || (millis() - _lastSend > 1000)) {
|
||||
std::lock_guard<std::mutex> lock(_msgLock);
|
||||
if (_ws && _buff_pos > 0) {
|
||||
_ws->textAll(_buffer, _buff_pos);
|
||||
_buff_pos = 0;
|
||||
}
|
||||
if (_forceSend) {
|
||||
_buff_pos = 0;
|
||||
}
|
||||
_forceSend = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "MqttHandleDtu.h"
|
||||
#include "Configuration.h"
|
||||
@ -10,11 +10,14 @@
|
||||
|
||||
MqttHandleDtuClass MqttHandleDtu;
|
||||
|
||||
MqttHandleDtuClass::MqttHandleDtuClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&MqttHandleDtuClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void MqttHandleDtuClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&MqttHandleDtuClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(Configuration.get().Mqtt.PublishInterval * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
@ -35,4 +38,4 @@ void MqttHandleDtuClass::loop()
|
||||
MqttSettings.publish("dtu/rssi", String(WiFi.RSSI()));
|
||||
MqttSettings.publish("dtu/bssid", WiFi.BSSIDstr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "MqttHandleHass.h"
|
||||
#include "MqttHandleInverter.h"
|
||||
@ -11,11 +11,14 @@
|
||||
|
||||
MqttHandleHassClass MqttHandleHass;
|
||||
|
||||
MqttHandleHassClass::MqttHandleHassClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&MqttHandleHassClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void MqttHandleHassClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&MqttHandleHassClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
@ -53,7 +56,7 @@ void MqttHandleHassClass::publishConfig()
|
||||
|
||||
const CONFIG_T& config = Configuration.get();
|
||||
|
||||
// publish DTU sensors
|
||||
// publish DTU sensors
|
||||
publishDtuSensor("IP", "", "diagnostic", "mdi:network-outline", "", "");
|
||||
publishDtuSensor("WiFi Signal", "signal_strength", "diagnostic", "", "dBm", "rssi");
|
||||
publishDtuSensor("Uptime", "duration", "diagnostic", "", "s", "");
|
||||
@ -104,7 +107,7 @@ void MqttHandleHassClass::publishInverterField(std::shared_ptr<InverterAbstract>
|
||||
const String serial = inv->serialString();
|
||||
|
||||
String fieldName;
|
||||
if (type == TYPE_AC && fieldType.fieldId == FLD_PDC) {
|
||||
if (type == TYPE_INV && fieldType.fieldId == FLD_PDC) {
|
||||
fieldName = "PowerDC";
|
||||
} else {
|
||||
fieldName = inv->Statistics()->getChannelFieldName(type, channel, fieldType.fieldId);
|
||||
@ -421,5 +424,5 @@ void MqttHandleHassClass::publish(const String& subtopic, const String& payload)
|
||||
{
|
||||
String topic = Configuration.get().Mqtt.Hass.Topic;
|
||||
topic += subtopic;
|
||||
MqttSettings.publishGeneric(topic.c_str(), payload.c_str(), Configuration.get().Mqtt.Hass.Retain);
|
||||
}
|
||||
MqttSettings.publishGeneric(topic, payload, Configuration.get().Mqtt.Hass.Retain);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "MqttHandleInverter.h"
|
||||
#include "MessageOutput.h"
|
||||
@ -18,6 +18,11 @@
|
||||
|
||||
MqttHandleInverterClass MqttHandleInverter;
|
||||
|
||||
MqttHandleInverterClass::MqttHandleInverterClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&MqttHandleInverterClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void MqttHandleInverterClass::init(Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
@ -28,16 +33,14 @@ void MqttHandleInverterClass::init(Scheduler& scheduler)
|
||||
using std::placeholders::_6;
|
||||
|
||||
const String topic = MqttSettings.getPrefix();
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART).c_str(), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
||||
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&MqttHandleInverterClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(Configuration.get().Mqtt.PublishInterval * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
@ -68,10 +71,7 @@ void MqttHandleInverterClass::loop()
|
||||
MqttSettings.publish(subtopic + "/device/fwbuildversion", String(inv->DevInfo()->getFwBuildVersion()));
|
||||
|
||||
// Firmware Build DateTime
|
||||
char timebuffer[32];
|
||||
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
||||
std::strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", gmtime(&t));
|
||||
MqttSettings.publish(subtopic + "/device/fwbuilddatetime", String(timebuffer));
|
||||
MqttSettings.publish(subtopic + "/device/fwbuilddatetime", inv->DevInfo()->getFwBuildDateTimeStr());
|
||||
|
||||
// Hardware part number
|
||||
MqttSettings.publish(subtopic + "/device/hwpartnumber", String(inv->DevInfo()->getHwPartNumber()));
|
||||
@ -141,7 +141,7 @@ String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv,
|
||||
}
|
||||
|
||||
String chanName;
|
||||
if (type == TYPE_AC && fieldId == FLD_PDC) {
|
||||
if (type == TYPE_INV && fieldId == FLD_PDC) {
|
||||
chanName = "powerdc";
|
||||
} else {
|
||||
chanName = inv->Statistics()->getChannelFieldName(type, channel, fieldId);
|
||||
@ -246,4 +246,4 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
MessageOutput.println("Ignored because retained");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "MqttHandleInverterTotal.h"
|
||||
#include "Configuration.h"
|
||||
@ -10,11 +10,14 @@
|
||||
|
||||
MqttHandleInverterTotalClass MqttHandleInverterTotal;
|
||||
|
||||
MqttHandleInverterTotalClass::MqttHandleInverterTotalClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&MqttHandleInverterTotalClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void MqttHandleInverterTotalClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&MqttHandleInverterTotalClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(Configuration.get().Mqtt.PublishInterval * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ void MqttSettingsClass::performConnect()
|
||||
} else {
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setCredentials(config.Mqtt.Username, config.Mqtt.Password);
|
||||
}
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setWill(willTopic.c_str(), 2, config.Mqtt.Retain, config.Mqtt.Lwt.Value_Offline);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setWill(willTopic.c_str(), config.Mqtt.Lwt.Qos, config.Mqtt.Retain, config.Mqtt.Lwt.Value_Offline);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setClientId(clientId.c_str());
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setCleanSession(config.Mqtt.CleanSession);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
|
||||
@ -223,4 +223,4 @@ void MqttSettingsClass::createMqttClientObject()
|
||||
}
|
||||
}
|
||||
|
||||
MqttSettingsClass MqttSettings;
|
||||
MqttSettingsClass MqttSettings;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "NetworkSettings.h"
|
||||
#include "Configuration.h"
|
||||
@ -12,7 +12,8 @@
|
||||
#include <ETH.h>
|
||||
|
||||
NetworkSettingsClass::NetworkSettingsClass()
|
||||
: _apIp(192, 168, 4, 1)
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&NetworkSettingsClass::loop, this))
|
||||
, _apIp(192, 168, 4, 1)
|
||||
, _apNetmask(255, 255, 255, 0)
|
||||
{
|
||||
_dnsServer.reset(new DNSServer());
|
||||
@ -29,8 +30,6 @@ void NetworkSettingsClass::init(Scheduler& scheduler)
|
||||
setupMode();
|
||||
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&NetworkSettingsClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "SunPosition.h"
|
||||
#include "Configuration.h"
|
||||
@ -10,15 +10,13 @@
|
||||
SunPositionClass SunPosition;
|
||||
|
||||
SunPositionClass::SunPositionClass()
|
||||
: _loopTask(5 * TASK_SECOND, TASK_FOREVER, std::bind(&SunPositionClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void SunPositionClass::init(Scheduler& scheduler)
|
||||
{
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&SunPositionClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.setInterval(5 * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
#include "Display_Graphic.h"
|
||||
#include "Led_Single.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "PinMapping.h"
|
||||
#include <Esp.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
uint32_t Utils::getChipId()
|
||||
{
|
||||
@ -76,3 +78,17 @@ bool Utils::checkJsonAlloc(const DynamicJsonDocument& doc, const char* function,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Remove all files but the PINMAPPING_FILENAME
|
||||
void Utils::removeAllFiles()
|
||||
{
|
||||
auto root = LittleFS.open("/");
|
||||
auto file = root.getNextFileName();
|
||||
|
||||
while (file != "") {
|
||||
if (file != PINMAPPING_FILENAME) {
|
||||
LittleFS.remove(file);
|
||||
}
|
||||
file = root.getNextFileName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi.h"
|
||||
#include "Configuration.h"
|
||||
@ -14,58 +14,29 @@ WebApiClass::WebApiClass()
|
||||
|
||||
void WebApiClass::init(Scheduler& scheduler)
|
||||
{
|
||||
_webApiConfig.init(_server);
|
||||
_webApiDevice.init(_server);
|
||||
_webApiDevInfo.init(_server);
|
||||
_webApiDtu.init(_server);
|
||||
_webApiEventlog.init(_server);
|
||||
_webApiFirmware.init(_server);
|
||||
_webApiGridprofile.init(_server);
|
||||
_webApiInverter.init(_server);
|
||||
_webApiLimit.init(_server);
|
||||
_webApiMaintenance.init(_server);
|
||||
_webApiMqtt.init(_server);
|
||||
_webApiNetwork.init(_server);
|
||||
_webApiNtp.init(_server);
|
||||
_webApiPower.init(_server);
|
||||
_webApiPrometheus.init(_server);
|
||||
_webApiSecurity.init(_server);
|
||||
_webApiSysstatus.init(_server);
|
||||
_webApiWebapp.init(_server);
|
||||
_webApiWsConsole.init(_server);
|
||||
_webApiWsLive.init(_server);
|
||||
_webApiWsDatabase.init(_server);
|
||||
_webApiConfig.init(_server, scheduler);
|
||||
_webApiDevice.init(_server, scheduler);
|
||||
_webApiDevInfo.init(_server, scheduler);
|
||||
_webApiDtu.init(_server, scheduler);
|
||||
_webApiEventlog.init(_server, scheduler);
|
||||
_webApiFirmware.init(_server, scheduler);
|
||||
_webApiGridprofile.init(_server, scheduler);
|
||||
_webApiInverter.init(_server, scheduler);
|
||||
_webApiLimit.init(_server, scheduler);
|
||||
_webApiMaintenance.init(_server, scheduler);
|
||||
_webApiMqtt.init(_server, scheduler);
|
||||
_webApiNetwork.init(_server, scheduler);
|
||||
_webApiNtp.init(_server, scheduler);
|
||||
_webApiPower.init(_server, scheduler);
|
||||
_webApiPrometheus.init(_server, scheduler);
|
||||
_webApiSecurity.init(_server, scheduler);
|
||||
_webApiSysstatus.init(_server, scheduler);
|
||||
_webApiWebapp.init(_server, scheduler);
|
||||
_webApiWsConsole.init(_server, scheduler);
|
||||
_webApiWsLive.init(_server, scheduler);
|
||||
_webApiWsDatabase.init(_server, scheduler);
|
||||
|
||||
_server.begin();
|
||||
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setCallback(std::bind(&WebApiClass::loop, this));
|
||||
_loopTask.setIterations(TASK_FOREVER);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
void WebApiClass::loop()
|
||||
{
|
||||
_webApiConfig.loop();
|
||||
_webApiDevice.loop();
|
||||
_webApiDevInfo.loop();
|
||||
_webApiDtu.loop();
|
||||
_webApiEventlog.loop();
|
||||
_webApiFirmware.loop();
|
||||
_webApiGridprofile.loop();
|
||||
_webApiInverter.loop();
|
||||
_webApiLimit.loop();
|
||||
_webApiMaintenance.loop();
|
||||
_webApiMqtt.loop();
|
||||
_webApiNetwork.loop();
|
||||
_webApiNtp.loop();
|
||||
_webApiPower.loop();
|
||||
_webApiSecurity.loop();
|
||||
_webApiSysstatus.loop();
|
||||
_webApiWebapp.loop();
|
||||
_webApiWsConsole.loop();
|
||||
_webApiWsLive.loop();
|
||||
_webApiWsDatabase.loop();
|
||||
}
|
||||
|
||||
bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
|
||||
@ -115,4 +86,4 @@ void WebApiClass::writeConfig(JsonVariant& retMsg, const WebApiError code, const
|
||||
}
|
||||
}
|
||||
|
||||
WebApiClass WebApi;
|
||||
WebApiClass WebApi;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_config.h"
|
||||
#include "Configuration.h"
|
||||
@ -10,7 +10,7 @@
|
||||
#include <AsyncJson.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
void WebApiConfigClass::init(AsyncWebServer& server)
|
||||
void WebApiConfigClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
@ -19,20 +19,14 @@ void WebApiConfigClass::init(AsyncWebServer& server)
|
||||
using std::placeholders::_5;
|
||||
using std::placeholders::_6;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/config/get", HTTP_GET, std::bind(&WebApiConfigClass::onConfigGet, this, _1));
|
||||
_server->on("/api/config/delete", HTTP_POST, std::bind(&WebApiConfigClass::onConfigDelete, this, _1));
|
||||
_server->on("/api/config/list", HTTP_GET, std::bind(&WebApiConfigClass::onConfigListGet, this, _1));
|
||||
_server->on("/api/config/upload", HTTP_POST,
|
||||
server.on("/api/config/get", HTTP_GET, std::bind(&WebApiConfigClass::onConfigGet, this, _1));
|
||||
server.on("/api/config/delete", HTTP_POST, std::bind(&WebApiConfigClass::onConfigDelete, this, _1));
|
||||
server.on("/api/config/list", HTTP_GET, std::bind(&WebApiConfigClass::onConfigListGet, this, _1));
|
||||
server.on("/api/config/upload", HTTP_POST,
|
||||
std::bind(&WebApiConfigClass::onConfigUploadFinish, this, _1),
|
||||
std::bind(&WebApiConfigClass::onConfigUpload, this, _1, _2, _3, _4, _5, _6));
|
||||
}
|
||||
|
||||
void WebApiConfigClass::loop()
|
||||
{
|
||||
}
|
||||
|
||||
void WebApiConfigClass::onConfigGet(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (!WebApi.checkCredentials(request)) {
|
||||
@ -114,7 +108,7 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
LittleFS.remove(CONFIG_FILENAME);
|
||||
Utils::removeAllFiles();
|
||||
Utils::restartDtu();
|
||||
}
|
||||
|
||||
@ -186,4 +180,4 @@ void WebApiConfigClass::onConfigUpload(AsyncWebServerRequest* request, String fi
|
||||
// close the file handle as the upload is now done
|
||||
request->_tempFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,15 +9,13 @@
|
||||
#include <AsyncJson.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
void WebApiDatabaseClass::init(AsyncWebServer& server)
|
||||
void WebApiDatabaseClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/database", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabase, this, _1));
|
||||
_server->on("/api/databaseHour", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabaseHour, this, _1));
|
||||
_server->on("/api/databaseDay", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabaseDay, this, _1));
|
||||
server.on("/api/database", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabase, this, _1));
|
||||
server.on("/api/databaseHour", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabaseHour, this, _1));
|
||||
server.on("/api/databaseDay", HTTP_GET, std::bind(&WebApiDatabaseClass::onDatabaseDay, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDatabaseClass::loop()
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_device.h"
|
||||
#include "Configuration.h"
|
||||
@ -12,18 +12,12 @@
|
||||
#include "helper.h"
|
||||
#include <AsyncJson.h>
|
||||
|
||||
void WebApiDeviceClass::init(AsyncWebServer& server)
|
||||
void WebApiDeviceClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/device/config", HTTP_GET, std::bind(&WebApiDeviceClass::onDeviceAdminGet, this, _1));
|
||||
_server->on("/api/device/config", HTTP_POST, std::bind(&WebApiDeviceClass::onDeviceAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDeviceClass::loop()
|
||||
{
|
||||
server.on("/api/device/config", HTTP_GET, std::bind(&WebApiDeviceClass::onDeviceAdminGet, this, _1));
|
||||
server.on("/api/device/config", HTTP_POST, std::bind(&WebApiDeviceClass::onDeviceAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
||||
@ -83,7 +77,8 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
||||
display["screensaver"] = config.Display.ScreenSaver;
|
||||
display["contrast"] = config.Display.Contrast;
|
||||
display["language"] = config.Display.Language;
|
||||
display["diagramduration"] = config.Display.DiagramDuration;
|
||||
display["diagramduration"] = config.Display.Diagram.Duration;
|
||||
display["diagrammode"] = config.Display.Diagram.Mode;
|
||||
|
||||
auto leds = root.createNestedArray("led");
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
@ -161,13 +156,15 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
||||
config.Display.ScreenSaver = root["display"]["screensaver"].as<bool>();
|
||||
config.Display.Contrast = root["display"]["contrast"].as<uint8_t>();
|
||||
config.Display.Language = root["display"]["language"].as<uint8_t>();
|
||||
config.Display.DiagramDuration = root["display"]["diagramduration"].as<uint32_t>();
|
||||
config.Display.Diagram.Duration = root["display"]["diagramduration"].as<uint32_t>();
|
||||
config.Display.Diagram.Mode = root["display"]["diagrammode"].as<DiagramMode_t>();
|
||||
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
config.Led_Single[i].Brightness = root["led"][i]["brightness"].as<uint8_t>();
|
||||
config.Led_Single[i].Brightness = min<uint8_t>(100, config.Led_Single[i].Brightness);
|
||||
}
|
||||
|
||||
Display.setDiagramMode(static_cast<DiagramMode_t>(config.Display.Diagram.Mode));
|
||||
Display.setOrientation(config.Display.Rotation);
|
||||
Display.enablePowerSafe = config.Display.PowerSafe;
|
||||
Display.enableScreensaver = config.Display.ScreenSaver;
|
||||
@ -183,4 +180,4 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
||||
if (performRestart) {
|
||||
Utils::restartDtu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_devinfo.h"
|
||||
#include "WebApi.h"
|
||||
@ -8,17 +8,11 @@
|
||||
#include <Hoymiles.h>
|
||||
#include <ctime>
|
||||
|
||||
void WebApiDevInfoClass::init(AsyncWebServer& server)
|
||||
void WebApiDevInfoClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/devinfo/status", HTTP_GET, std::bind(&WebApiDevInfoClass::onDevInfoStatus, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDevInfoClass::loop()
|
||||
{
|
||||
server.on("/api/devinfo/status", HTTP_GET, std::bind(&WebApiDevInfoClass::onDevInfoStatus, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
||||
@ -46,13 +40,9 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
||||
root["hw_version"] = inv->DevInfo()->getHwVersion();
|
||||
root["hw_model_name"] = inv->DevInfo()->getHwModelName();
|
||||
root["max_power"] = inv->DevInfo()->getMaxPower();
|
||||
|
||||
char timebuffer[32];
|
||||
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
||||
std::strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", gmtime(&t));
|
||||
root["fw_build_datetime"] = String(timebuffer);
|
||||
root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr();
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Thomas Basler and others
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_dtu.h"
|
||||
#include "Configuration.h"
|
||||
@ -9,18 +9,32 @@
|
||||
#include <AsyncJson.h>
|
||||
#include <Hoymiles.h>
|
||||
|
||||
void WebApiDtuClass::init(AsyncWebServer& server)
|
||||
WebApiDtuClass::WebApiDtuClass()
|
||||
: _applyDataTask(TASK_IMMEDIATE, TASK_ONCE, std::bind(&WebApiDtuClass::applyDataTaskCb, this))
|
||||
{
|
||||
}
|
||||
|
||||
void WebApiDtuClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
server.on("/api/dtu/config", HTTP_GET, std::bind(&WebApiDtuClass::onDtuAdminGet, this, _1));
|
||||
server.on("/api/dtu/config", HTTP_POST, std::bind(&WebApiDtuClass::onDtuAdminPost, this, _1));
|
||||
|
||||
_server->on("/api/dtu/config", HTTP_GET, std::bind(&WebApiDtuClass::onDtuAdminGet, this, _1));
|
||||
_server->on("/api/dtu/config", HTTP_POST, std::bind(&WebApiDtuClass::onDtuAdminPost, this, _1));
|
||||
scheduler.addTask(_applyDataTask);
|
||||
}
|
||||
|
||||
void WebApiDtuClass::loop()
|
||||
void WebApiDtuClass::applyDataTaskCb()
|
||||
{
|
||||
// Execute stuff in main thread to avoid busy SPI bus
|
||||
CONFIG_T& config = Configuration.get();
|
||||
Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu.Nrf.PaLevel);
|
||||
Hoymiles.getRadioCmt()->setPALevel(config.Dtu.Cmt.PaLevel);
|
||||
Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu.Serial);
|
||||
Hoymiles.getRadioCmt()->setDtuSerial(config.Dtu.Serial);
|
||||
Hoymiles.getRadioCmt()->setCountryMode(static_cast<CountryModeId_t>(config.Dtu.Cmt.CountryMode));
|
||||
Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency);
|
||||
Hoymiles.setPollInterval(config.Dtu.PollInterval);
|
||||
}
|
||||
|
||||
void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
|
||||
@ -45,6 +59,19 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
|
||||
root["cmt_enabled"] = Hoymiles.getRadioCmt()->isInitialized();
|
||||
root["cmt_palevel"] = config.Dtu.Cmt.PaLevel;
|
||||
root["cmt_frequency"] = config.Dtu.Cmt.Frequency;
|
||||
root["cmt_country"] = config.Dtu.Cmt.CountryMode;
|
||||
root["cmt_chan_width"] = Hoymiles.getRadioCmt()->getChannelWidth();
|
||||
|
||||
auto data = root.createNestedArray("country_def");
|
||||
auto countryDefs = Hoymiles.getRadioCmt()->getCountryFrequencyList();
|
||||
for (const auto& definition : countryDefs) {
|
||||
auto obj = data.createNestedObject();
|
||||
obj["freq_default"] = definition.definition.Freq_Default;
|
||||
obj["freq_min"] = definition.definition.Freq_Min;
|
||||
obj["freq_max"] = definition.definition.Freq_Max;
|
||||
obj["freq_legal_min"] = definition.definition.Freq_Legal_Min;
|
||||
obj["freq_legal_max"] = definition.definition.Freq_Legal_Max;
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
@ -93,7 +120,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
||||
&& root.containsKey("pollinterval")
|
||||
&& root.containsKey("nrf_palevel")
|
||||
&& root.containsKey("cmt_palevel")
|
||||
&& root.containsKey("cmt_frequency"))) {
|
||||
&& root.containsKey("cmt_frequency")
|
||||
&& root.containsKey("cmt_country"))) {
|
||||
retMsg["message"] = "Values are missing!";
|
||||
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||
response->setLength();
|
||||
@ -133,14 +161,23 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
||||
return;
|
||||
}
|
||||
|
||||
if (root["cmt_frequency"].as<uint32_t>() < Hoymiles.getRadioCmt()->getMinFrequency()
|
||||
|| root["cmt_frequency"].as<uint32_t>() > Hoymiles.getRadioCmt()->getMaxFrequency()
|
||||
|| root["cmt_frequency"].as<uint32_t>() % 250 > 0) {
|
||||
if (root["cmt_country"].as<uint8_t>() >= CountryModeId_t::CountryModeId_Max) {
|
||||
retMsg["message"] = "Invalid country setting!";
|
||||
retMsg["code"] = WebApiError::DtuInvalidCmtCountry;
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
auto FrequencyDefinition = Hoymiles.getRadioCmt()->getCountryFrequencyList()[root["cmt_country"].as<CountryModeId_t>()].definition;
|
||||
if (root["cmt_frequency"].as<uint32_t>() < FrequencyDefinition.Freq_Min
|
||||
|| root["cmt_frequency"].as<uint32_t>() > FrequencyDefinition.Freq_Max
|
||||
|| root["cmt_frequency"].as<uint32_t>() % Hoymiles.getRadioCmt()->getChannelWidth() > 0) {
|
||||
|
||||
retMsg["message"] = "Invalid CMT frequency setting!";
|
||||
retMsg["code"] = WebApiError::DtuInvalidCmtFrequency;
|
||||
retMsg["param"]["min"] = Hoymiles.getRadioCmt()->getMinFrequency();
|
||||
retMsg["param"]["max"] = Hoymiles.getRadioCmt()->getMaxFrequency();
|
||||
retMsg["param"]["min"] = FrequencyDefinition.Freq_Min;
|
||||
retMsg["param"]["max"] = FrequencyDefinition.Freq_Max;
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
return;
|
||||
@ -154,16 +191,12 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
||||
config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as<uint8_t>();
|
||||
config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as<int8_t>();
|
||||
config.Dtu.Cmt.Frequency = root["cmt_frequency"].as<uint32_t>();
|
||||
config.Dtu.Cmt.CountryMode = root["cmt_country"].as<CountryModeId_t>();
|
||||
|
||||
WebApi.writeConfig(retMsg);
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu.Nrf.PaLevel);
|
||||
Hoymiles.getRadioCmt()->setPALevel(config.Dtu.Cmt.PaLevel);
|
||||
Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu.Serial);
|
||||
Hoymiles.getRadioCmt()->setDtuSerial(config.Dtu.Serial);
|
||||
Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency);
|
||||
Hoymiles.setPollInterval(config.Dtu.PollInterval);
|
||||
}
|
||||
_applyDataTask.enable();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user