Compare commits

..

No commits in common. "master" and "v23.4.12" have entirely different histories.

387 changed files with 10964 additions and 28035 deletions

View File

@ -1,9 +0,0 @@
# http://editorconfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

View File

@ -5,18 +5,11 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: > value: >
### ⚠️ Please remember: issues are for *bugs* ### ✋ **This is bug tracker, not a support forum**
That is, something you believe affects every single user of OpenDTU, not just you. If you're not sure, start with one of the other options below.
- type: markdown
attributes:
value: |
#### Have a question? 👉 [Start a new discussion](https://github.com/tbnobody/OpenDTU/discussions/new) or [ask in chat](https://discord.gg/WzhxEY62mB).
#### Before opening an issue, please double check: If something isn't working right, you have questions or need help, [**get in touch on the Discussions**](https://github.com/tbnobody/OpenDTU/discussions).
- [Documentation](https://www.opendtu.solar). Please quickly search existing issues first before submitting a bug.
- [The FAQs](https://www.opendtu.solar/firmware/faq/).
- [Existing issues and discussions](https://github.com/tbnobody/OpenDTU/search?q=&type=issues).
- type: textarea - type: textarea
id: what-happened id: what-happened
attributes: attributes:
@ -47,8 +40,7 @@ body:
label: Install Method label: Install Method
description: How did you install OpenDTU? description: How did you install OpenDTU?
options: options:
- Pre-Compiled binary from GitHub releases - Pre-Compiled binary from GitHub
- Pre-Compiled binary from GitHub actions/pull-request
- Self-Compiled - Self-Compiled
validations: validations:
required: true required: true
@ -60,14 +52,6 @@ body:
placeholder: "e.g. 359d513" placeholder: "e.g. 359d513"
validations: validations:
required: true required: true
- type: input
id: environment
attributes:
label: What firmware variant (PIO Environment) are you using?
description: You can find this in by going to Info -> System
placeholder: "generic_esp32s3_usb"
validations:
required: true
- type: textarea - type: textarea
id: logs id: logs
attributes: attributes:
@ -82,16 +66,3 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations: validations:
required: false required: false
- type: checkboxes
id: required-checks
attributes:
label: Please confirm the following
options:
- label: I believe this issue is a bug that affects all users of OpenDTU, not something specific to my installation.
required: true
- label: I have already searched for relevant existing issues and discussions before opening this report.
required: true
- label: I have updated the title field above with a concise description.
required: true
- label: I have double checked that my inverter does not contain a W in the model name (like HMS-xxxW) as they are not supported.
required: true

View File

@ -15,17 +15,17 @@ jobs:
name: Gather Environments name: Gather Environments
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Cache pip - name: Cache pip
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: ~/.cache/pip path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: | restore-keys: |
${{ runner.os }}-pip- ${{ runner.os }}-pip-
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
@ -37,26 +37,26 @@ jobs:
- name: Get default environments - name: Get default environments
id: envs id: envs
run: | run: |
echo "environments=$(pio project config --json-output | jq -cr '.[1][1][0][1]|split(",")')" >> $GITHUB_OUTPUT echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
outputs: outputs:
environments: ${{ steps.envs.outputs.environments }} environments: ${{ steps.envs.outputs.environments }}
build: build:
name: Build Environments name: Build Enviornments
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: get_default_envs needs: get_default_envs
strategy: strategy:
matrix: matrix:
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Get tags - name: Get tags
run: git fetch --force --tags origin run: git fetch --force --tags origin
- name: Cache pip - name: Cache pip
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: ~/.cache/pip path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
@ -64,42 +64,33 @@ jobs:
${{ runner.os }}-pip- ${{ runner.os }}-pip-
- name: Cache PlatformIO - name: Cache PlatformIO
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: ~/.platformio path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
- name: Install PlatformIO - name: Install PlatformIO
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade platformio setuptools pip install --upgrade platformio
- name: Enable Corepack
run: |
cd webapp
corepack enable
- name: Setup Node.js and yarn - name: Setup Node.js and yarn
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: "22" node-version: "18"
cache: "yarn" cache: "yarn"
cache-dependency-path: "webapp/yarn.lock" cache-dependency-path: "webapp/yarn.lock"
- name: Install WebApp dependencies - name: Install WebApp dependencies
run: | run: yarn --cwd webapp install --frozen-lockfile
cd webapp
yarn install --frozen-lockfile
- name: Build WebApp - name: Build WebApp
run: | run: yarn --cwd webapp build
cd webapp
yarn build
- name: Build firmware - name: Build firmware
run: pio run -e ${{ matrix.environment }} run: pio run -e ${{ matrix.environment }}
@ -107,15 +98,17 @@ jobs:
- name: Rename Firmware - name: Rename Firmware
run: mv .pio/build/${{ matrix.environment }}/firmware.bin .pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.bin run: mv .pio/build/${{ matrix.environment }}/firmware.bin .pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.bin
- name: Rename Factory Firmware - name: Copy boot_app0.bin
run: mv .pio/build/${{ matrix.environment }}/firmware.factory.bin .pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.factory.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin .pio/build/${{ matrix.environment }}/boot_app0.bin
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: opendtu-${{ matrix.environment }} name: opendtu-${{ matrix.environment }}
path: | path: |
.pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.bin .pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.bin
.pio/build/${{ matrix.environment }}/opendtu-${{ matrix.environment }}.factory.bin .pio/build/${{ matrix.environment }}/partitions.bin
.pio/build/${{ matrix.environment }}/bootloader.bin
.pio/build/${{ matrix.environment }}/boot_app0.bin
release: release:
name: Create Release name: Create Release
@ -124,11 +117,11 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Build Changelog - name: Build Changelog
id: github_release id: github_release
uses: mikepenz/release-changelog-builder-action@v4 uses: mikepenz/release-changelog-builder-action@v3.7.0
with: with:
failOnError: true failOnError: true
commitMode: true commitMode: true
@ -136,18 +129,20 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v3
with: with:
path: artifacts/ path: artifacts/
- name: Move all files to the same location - name: Create ZIPs
run: | run: |
ls -R ls -R
sudo apt install zip
cd artifacts cd artifacts
for i in */; do zip -r "${i%/}.zip" "$i"; done
for i in */; do cp ${i}opendtu-*.bin ./; done for i in */; do cp ${i}opendtu-*.bin ./; done
- name: Create release - name: Create release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v1
with: with:
body: ${{steps.github_release.outputs.changelog}} body: ${{steps.github_release.outputs.changelog}}
draft: False draft: False

View File

@ -18,12 +18,6 @@
"fix" "fix"
] ]
}, },
{
"title": "## 🌎 Web Application",
"labels": [
"webapp"
]
},
{ {
"title": "## 📚 Documentation", "title": "## 📚 Documentation",
"labels": [ "labels": [

View File

@ -7,9 +7,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
- name: Install dependencies - name: Install dependencies
@ -18,4 +18,4 @@ jobs:
pip install cpplint pip install cpplint
- name: Linting - name: Linting
run: | run: |
cpplint --repository=. --recursive --filter=-build/c++11,-runtime/references,-readability/braces,-whitespace,-legal,-build/include ./src ./include ./lib/Hoymiles ./lib/MqttSubscribeParser ./lib/TimeoutHelper ./lib/ResetReason cpplint --repository=. --recursive --filter=-runtime/references,-readability/braces,-whitespace,-legal,-build/include ./src ./include ./lib/Hoymiles ./lib/MqttSubscribeParser ./lib/TimeoutHelper ./lib/ResetReason

View File

@ -1,54 +0,0 @@
name: 'Repository Maintenance'
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock
jobs:
stale:
name: 'Stale'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
days-before-stale: 14
days-before-close: 60
any-of-labels: 'cant-reproduce,not a bug'
stale-issue-label: stale
stale-pr-label: stale
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
lock-threads:
name: 'Lock Old Threads'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: '30'
pr-inactive-days: '30'
discussion-inactive-days: '30'
log-output: true
issue-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new discussion or issue for related concerns.
pr-comment: >
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new discussion or issue for related concerns.
discussion-comment: >
This discussion has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new discussion for related concerns.

View File

@ -6,23 +6,17 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
defaults:
run:
working-directory: webapp
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js and yarn - name: Setup Node.js and yarn
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: "22" node-version: "18"
cache: "yarn" cache: "yarn"
cache-dependency-path: "webapp/yarn.lock" cache-dependency-path: "webapp/yarn.lock"
- name: Install WebApp dependencies - name: Install WebApp dependencies
run: yarn install --frozen-lockfile run: yarn --cwd webapp install --frozen-lockfile
- name: Linting - name: Linting
run: yarn lint run: yarn --cwd webapp lint

View File

@ -1,28 +0,0 @@
name: Yarn Prettier
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: webapp
steps:
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js and yarn
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "yarn"
cache-dependency-path: "webapp/yarn.lock"
- name: Install WebApp dependencies
run: yarn install --frozen-lockfile
- name: Check Formatting
run: yarn prettier --check src/

1
.gitignore vendored
View File

@ -5,6 +5,5 @@
.vscode/ipch .vscode/ipch
.vscode/settings.json .vscode/settings.json
platformio-device-monitor*.log platformio-device-monitor*.log
logs/device-monitor*.log
platformio_override.ini platformio_override.ini
.DS_Store .DS_Store

View File

@ -2,9 +2,6 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846 // See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format // for the documentation about the extensions.json format
"recommendations": [ "recommendations": [
"DavidAnson.vscode-markdownlint",
"EditorConfig.EditorConfig",
"Vue.volar",
"platformio.platformio-ide" "platformio.platformio-ide"
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [

294
README.md
View File

@ -13,23 +13,76 @@ If you are upgrading from a version before 15.03.2023 you have to upgrade the pa
This project was started from [this](https://www.mikrocontroller.net/topic/525778) discussion (Mikrocontroller.net). This project was started from [this](https://www.mikrocontroller.net/topic/525778) discussion (Mikrocontroller.net).
It was the goal to replace the original Hoymiles DTU (Telemetry Gateway) with their cloud access. With a lot of reverse engineering the Hoymiles protocol was decrypted and analyzed. It was the goal to replace the original Hoymiles DTU (Telemetry Gateway) with their cloud access. With a lot of reverse engineering the Hoymiles protocol was decrypted and analyzed.
## Documentation ## Screenshots
The documentation can be found [here](https://tbnobody.github.io/OpenDTU-docs/). Several screenshots of the frontend can be found here: [Screenshots](docs/screenshots/README.md)
Please feel free to support and create a PR in [this](https://github.com/tbnobody/OpenDTU-docs) repository to make the documentation even better.
## Builds
Different builds from existing installations can be found here [Builds](docs/builds/README.md)
Like to show your own build? Just send me a Pull Request.
## Currently supported Inverters
* Hoymiles HM-300
* Hoymiles HM-350
* Hoymiles HM-400
* Hoymiles HM-600
* Hoymiles HM-700
* Hoymiles HM-800
* Hoymiles HM-1000
* Hoymiles HM-1200
* Hoymiles HM-1500
* Solenso SOL-H350
* Solenso SOL-H400
* Solenso SOL-H800
* TSUN TSOL-M350 (Maybe depending on firmware/serial number on the inverter)
* TSUN TSOL-M800 (Maybe depending on firmware/serial number on the inverter)
* TSUN TSOL-M1600 (Maybe depending on firmware/serial number on the inverter)
**TSUN compatibility remark:**
Compatibility with OpenDTU seems to be related to serial numbers. Current findings indicate that TSUN inverters with a serial number starting with "11" are supported, whereby inverters with a serial number starting with "10" are not.
Firmware version seems to play not a significant role and cannot be read from the stickers. For completeness, the following firmware version have been reported to work with OpenDTU:
* v1.0.8, v1.0.10 TSOL-M800 (DE)
* v1.0.12 TSOL-M1600
## Features for end users
* Read live data from inverter
* Show inverters internal event log
* Show inverter information like firmware version, firmware build date, hardware revision and hardware version
* Show and set the current inverter limit
* Function to turn the inverter off and on
* Uses ESP32 microcontroller and NRF24L01+
* Multi-Inverter support
* MQTT support (with TLS)
* Home Assistant MQTT Auto Discovery support
* Nice and fancy WebApp with visualization of current data
* Firmware upgrade using the web UI
* Default source supports up to 10 inverters
* Time zone support
* Ethernet support
* Prometheus API endpoint (/api/prometheus/metrics)
* English, german and french web interface
* Displays (SSD1306, SH1106, PCD8544)
* Dark Theme
## Features for developers
* The microcontroller part
* Build with Arduino PlatformIO Framework for the ESP32
* Uses a fork of [ESPAsyncWebserver](https://github.com/yubox-node-org/ESPAsyncWebServer) and [espMqttClient](https://github.com/bertmelis/espMqttClient)
* The WebApp part
* Build with [Vue.js](https://vuejs.org)
* Source is written in TypeScript
## Breaking changes ## Breaking changes
Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | grep BREAKING` Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | grep BREAKING`
```code ```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=
* 318136d 2023-03-15 BREAKING CHANGE: Updated partition table: Make sure you have a configuration backup and completly reflash the device! * 318136d 2023-03-15 BREAKING CHANGE: Updated partition table: Make sure you have a configuration backup and completly reflash the device!
* 3b7aef6 2023-02-13 BREAKING CHANGE: Web API! * 3b7aef6 2023-02-13 BREAKING CHANGE: Web API!
* d4c838a 2023-02-06 BREAKING CHANGE: Prometheus API! * d4c838a 2023-02-06 BREAKING CHANGE: Prometheus API!
@ -38,6 +91,223 @@ Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | gre
* 27ed4e3 2022-10-31 BREAKING: Change power factor from percent value to value between 0 and 1 * 27ed4e3 2022-10-31 BREAKING: Change power factor from percent value to value between 0 and 1
``` ```
## Currently supported Inverters ## Hardware you need
A list of all currently supported inverters can be found [here](https://www.opendtu.solar/hardware/inverter_overview/) ### 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:
![NodeMCU-ESP32](docs/nodemcu-esp32.png)
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)
### NRF24L01+ radio board
The PLUS sign is IMPORTANT! There are different variants available, with antenna on the printed circuit board or external antenna.
Sample picture:
![nrf24l01plus](docs/nrf24l01plus.png)
Buy your hardware from a trusted source, at best from a dealer/online shop in your country where you have support and the right to return non-functional hardware.
When you want to buy from Amazon, AliExpress, eBay etc., take note that there is a lot of low-quality or fake hardware offered. Read customer comments and ratings carefully!
A heavily incomplete list of trusted hardware shops in germany is:
* [AZ-Delivery](https://www.az-delivery.de/)
* [Makershop](https://www.makershop.de/)
* [Berrybase](https://www.berrybase.de/)
This list is for your convenience only, the project is not related to any of these shops.
### Power supply
Use a power suppy with 5 V and 1 A. The USB cable connected to your PC/Notebook may be powerful enough or may be not.
## Wiring up
### Schematic
![Schematic](docs/Wiring_ESP32_Schematic.png)
### Symbolic view
![Symbolic](docs/Wiring_ESP32_Symbol.png)
### 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.
## Flashing and starting up
### with Visual Studio Code
* Install [Visual Studio Code](https://code.visualstudio.com/download) (from now named "vscode")
* In Visual Studio Code, install the [PlatformIO Extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide)
* Install git and enable git in vscode - [git download](https://git-scm.com/downloads/) - [Instructions](https://www.jcchouinard.com/install-git-in-vscode/)
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur): Inside vscode open the command palette by pressing `CTRL` + `SHIFT` + `P`. Enter `git clone`, add the repository-URL `https://github.com/tbnobody/OpenDTU`. Next you have to choose (or create) a target directory.
* In vscode, choose File --> Open Folder and select the previously downloaded source code. (You have to select the folder which contains the "platformio.ini" and "platformio_override.ini" file)
* Adjust the COM port in the file "platformio_override.ini" for your USB-to-serial-converter. It occurs twice:
* upload_port
* monitor_port
* Select the arrow button in the blue bottom status bar (PlatformIO: Upload) to compile and upload the firmware. During the compilation, all required libraries are downloaded automatically.
* Under Linux, if the upload fails with error messages "Could not open /dev/ttyUSB0, the port doesn't exist", you can check via ```ls -la /dev/tty*``` to which group your port belongs to, and then add your user this group via ```sudo adduser <yourusername> dialout``` (if you are using ```arch-linux``` use: ```sudo gpasswd -a <yourusername> uucp```, this method requires a logout/login of the affected user).
* There are two videos showing these steps:
* [Git Clone and compilation](https://youtu.be/9cA_esv3zeA)
* [Full installation and compilation](https://youtu.be/xs6TqHn7QWM)
### on the commandline with PlatformIO Core
* Install [PlatformIO Core](https://platformio.org/install/cli)
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur)
* Adjust the COM port in the file "platformio_override.ini". It occurs twice:
* upload_port
* monitor_port
* build: `platformio run -e generic`
* upload to esp module: `platformio run -e generic -t upload`
* other options:
* clean the sources: `platformio run -e generic -t clean`
* erase flash: `platformio run -e generic -t erase`
### using the pre-compiled .bin files
The pre-compiled files can be found on the [github page](https://github.com/tbnobody/OpenDTU) in the tab "Actions" and the sub menu "OpenDTU Build". Just choose the latest build from the master branch (search for "master" in the blue font text but click on the white header text!). You need to be logged in with your github account to download the files.
Use a ESP32 flash tool of your choice (see next chapter) and flash the `.bin` files to the right addresses:
| Address | File |
| ---------| ---------------------- |
| 0x1000 | bootloader.bin |
| 0x8000 | partitions.bin |
| 0xe000 | boot_app0.bin |
| 0x10000 | opendtu-*.bin |
For further updates you can just use the web interface and upload the `opendtu-*.bin` file.
#### Flash with esptool.py (Linux)
```bash
esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_reset \
write_flash --flash_mode dout --flash_freq 40m --flash_size detect \
0x1000 bootloader.bin \
0x8000 partitions.bin \
0xe000 boot_app0.bin \
0x10000 opendtu-generic.bin
```
#### Flash with Espressif Flash Download Tool (Windows)
[Download link](https://www.espressif.com/en/support/download/other-tools)
* On startup, select Chip Type -> "ESP32" / WorkMode -> "Develop"
* Prepare all settings (see picture). Make sure to uncheck the `DoNotChgBin` option. Otherwise you may get errors like "invalid header".
* ![flash tool image](docs/esp32_flash_download_tool.png)
* Press "Erase" button on screen. Look into the terminal window, you should see dots appear. Then press the "Boot" button on the ESP32 board. Wait for "FINISH" to see if flashing/erasing is done.
* To program, press "Start" on screen, then the "Boot" button.
* When flashing is complete (FINISH appears) then press the Reset button on the ESP32 board (or powercycle ) to start the OpenDTU application.
#### Flash with ESP_Flasher (Windows)
Users report that [ESP_Flasher](https://github.com/Jason2866/ESP_Flasher/releases/) is suitable for flashing OpenDTU on Windows.
#### Flash with [ESP_Flasher](https://espressif.github.io/esptool-js/) - web version
It is also possible to flash it via the web tools which might be more convenient and is platform independent.
## First configuration
* After the initial flashing of the microcontroller, an Access Point called "OpenDTU-*" is opened. The default password is "openDTU42".
* Use a web browser to open the address [http://192.168.4.1](http://192.168.4.1)
* Navigate to Settings --> Network Settings and enter your WiFi credentials. The username to access the config menu is "admin" and the password the same as for accessing the Access Point (default: "openDTU42").
* OpenDTU then simultaneously connects to your WiFi AP with these credentials. Navigate to Info --> Network and look into section "Network Interface (Station)" for the IP address received via DHCP.
* If your WiFi AP uses an allow-list for MAC-addresses, please be aware that the ESP32 has two different MAC addresses for its AP and client modes, they are also listed at Info --> Network.
* When OpenDTU is connected to a configured WiFI AP, the "OpenDTU-*" Access Point is closed after 3 minutes.
* OpenDTU needs access to a working NTP server to get the current date & time. Both are sent to the inverter with each request. Default NTP server is pool.ntp.org. If your network has different requirements please change accordingly (Settings --> NTP Settings).
* Add your inverter in the inverter settings (Settings --> Inverter Settings)
## Flashing an Update using "Over The Air" OTA Update
Once you have your OpenDTU running and connected to WLAN, you can do further updates through the web interface.
Navigate to Settings --> Firmware upgrade and press the browse button. Select the firmware file from your local computer.
You'll find the firmware file (after a successful build process) under `.pio/build/generic/firmware.bin`.
If you downloaded a precompiled zip archive, unpack it and choose `opendtu-generic.bin`.
After the successful upload, the OpenDTU immediately restarts into the new firmware.
## MQTT Topic Documentation
A documentation of all available MQTT Topics can be found here: [MQTT Documentation](docs/MQTT_Topics.md)
## Web API Documentation
A documentation of the Web API can be found here: [Web-API Documentation](docs/Web-API.md)
## Available cases
* <https://www.thingiverse.com/thing:5435911>
* <https://www.printables.com/model/293003-sol-opendtu-esp32-nrf24l01-case>
* <https://www.thingiverse.com/thing:5661780>
* <https://www.thingiverse.com/thing:5632374>
* <https://www.thingiverse.com/thing:5852233>
* <https://www.printables.com/model/377994-opendtu-pcb-box-for-the-wider-board>
* <https://www.printables.com/model/376840-esp32-ahoy-opendtu-pcb-housing>
## Available layouts for printed circuit boards
* [BreakoutBoard - sample printed circuit board for OpenDTU and Ahoy](https://github.com/dokuhn/openDTU-BreakoutBoard)
* [Board for OpenDTU with Display](https://github.com/SteffMUC/openDTU_wDisplay2)
* [OpenDTU PCB mit Display](https://github.com/turrican944/OpenDTU-PCB)
* [PCB for OpenDTU in Cable Branchbox](https://github.com/plewka/ESP-Solar_OpenDTU)
## Building
* Building the WebApp
* The WebApp can be build using yarn
```bash
cd webapp
yarn install
yarn build
```
* The updated output is placed in the 'webapp_dist' directory
* It is only necessary to build the webapp when you made changes to it
* Building the microcontroller firmware
* Visual Studio Code with the PlatformIO Extension is required for building
## Troubleshooting
* First: When there is no light on the solar panels, the inverter completely turns off and does not answer to OpenDTU! So if you assembled your OpenDTU in the evening, wait until tomorrow.
* When there is no data received from the inverter(s) - try to reduce the distance between the openDTU and the inverter (e.g. move it to the window towards the roof)
* Under Settings -> DTU Settings you can increase the transmit power "PA level". Default is "minimum".
* The NRF24L01+ needs relatively much current. With bad power supply (and especially bad cables!) a 10 µF capacitor soldered directly to the NRF24L01+ board connector brings more stability (pin 1+2 are the power supply). Note the polarity of the capacitor…
* You can try to use an USB power supply with 1 A or more instead of connecting the ESP32 to the computer.
* Try a different USB cable. Once again, a stable power source is important. Some USB cables are made of much plastic and very little copper inside.
* Double check that you have a radio module NRF24L01+ with a plus sign at the end. NRF24L01 module without the plus are not compatible with this project.
* There is no possibility of auto-discovering the inverters. Double check you have entered the serial numbers of the inverters correctly.
* OpenDTU needs access to a working NTP server to get the current date & time.
* If your problem persists, check the [Issues on Github](https://github.com/tbnobody/OpenDTU/issues). Please inspect not only the open issues, also the closed issues contain useful information.
* Another source of information are the [Discussions](https://github.com/tbnobody/OpenDTU/discussions/)
* When flashing with VSCode Plattform.IO fails and also with ESPRESSIF tool a demo bin file cannot be flashed to the ESP32 with error message "A fatal error occurred: MD5 of file does not match data in flash!" than un-wire/unconnect ESP32 from the NRF24L01+ board. Try to flash again and rewire afterwards.
## Related Projects
* [Ahoy](https://github.com/grindylow/ahoy)
* [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles)
* [OpenDTU extended to talk to Victrons MPPT battery chargers (Ve.Direct)](https://github.com/helgeerbe/OpenDTU_VeDirect)

29
auto_firmware_version.py Normal file
View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2022 Thomas Basler and others
#
import pkg_resources
Import("env")
required_pkgs = {'dulwich'}
installed_pkgs = {pkg.key for pkg in pkg_resources.working_set}
missing_pkgs = required_pkgs - installed_pkgs
if missing_pkgs:
env.Execute('"$PYTHONEXE" -m pip install dulwich')
from dulwich import porcelain
def get_firmware_specifier_build_flag():
try:
build_version = porcelain.describe('.') # '.' refers to the repository root dir
except:
build_version = "g0000000"
build_flag = "-D AUTO_GIT_HASH=\\\"" + build_version + "\\\""
print ("Firmware Revision: " + build_version)
return (build_flag)
env.Append(
BUILD_FLAGS=[get_firmware_specifier_build_flag()]
)

View File

@ -1,3 +1,107 @@
# Device Profiles # Device Profiles
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/firmware/device_profiles/> It is possible to change hardware settings like pin assignments or ethernet support using a json file. The json file can be uploaded using the configuration management in the web interface. Just select "Pin Mapping (pin_mapping.json)" in the recovery section.
When the file is uploaded the ESP performs a reboot. This is required as the pin settings could have changed within the file. By default all the pin assignments are used as compiled into the firmware.
To change the device profile, navigate to the "Device Manager" and selected the appropriate profile. You can see the current (Active) and the new (Selected) in assignment in the table below the combobox.
## Structure of the json file
```json
[
{
"name": "Generic NodeMCU 38 pin",
"nrf24": {
"miso": 19,
"mosi": 23,
"clk": 18,
"irq": 16,
"en": 4,
"cs": 5
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": -1,
"clk_mode": -1
}
},
{
"name": "Generic NodeMCU 38 pin with SSD1306",
"nrf24": {
"miso": 19,
"mosi": 23,
"clk": 18,
"irq": 16,
"en": 4,
"cs": 5
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": -1,
"clk_mode": -1
},
"display": {
"type": 2,
"data": 21,
"clk": 22
}
},
{
"name": "Olimex ESP32-POE",
"nrf24": {
"miso": 15,
"mosi": 2,
"clk": 14,
"irq": 13,
"en": 16,
"cs": 5
},
"eth": {
"enabled": true,
"phy_addr": 0,
"power": 12,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 3
}
}
]
```
The json file can contain multiple profiles. Each profile requires a name and different parameters. If one parameter is not set, the default value, as compiled into the firmware is used. The example above shows all the currently supported values. Others may follow. Sample files for some boards can be found [here](DeviceProfiles/). This means you can just flash the generic bin file and upload the json file. Then you select your board and everything works hopyfully as expected.
## Implemented configuration values
| Parameter | Data Type | Description |
| ------------- | --------- | ----------- |
| name | string | Unique name of the profile (max 63 characters) |
| nrf24.miso | number | MISO Pin |
| nrf24.mosi | number | MOSI Pin |
| nrf24.clk | number | Clock Pin |
| nrf24.irq | number | Interrupt Pin |
| nrf24.en | number | Enable Pin |
| nrf24.cs | number | Chip Select Pin |
| eth.enabled | boolean | Enable/Disable the ethernet stack |
| eth.phy_addr | number | Unique PHY addr |
| eth.power | number | Power Pin (if available). Use -1 for not assigned pins. |
| eth.mdc | number | Serial Management Interface MDC Pin. Use -1 for not assigned pins. |
| eth.mdio | number | Serial Management Interface MDIO Pin. Use -1 for not assigned pins. |
| eth.type | number | Possible values:<br>* 0 = ETH_PHY_LAN8720<br>* 1 = ETH_PHY_TLK110<br>* 2 = ETH_PHY_RTL8201<br>* 3 = ETH_PHY_DP83848<br>* 4 = ETH_PHY_DM9051<br>* 5 = ETH_PHY_KSZ8041<br>* 6 = ETH_PHY_KSZ8081 |
| eth.clk_mode | number | Possible values:<br>* 0 = ETH_CLOCK_GPIO0_IN<br>* 1 = ETH_CLOCK_GPIO0_OUT<br>* 2 = ETH_CLOCK_GPIO16_OUT<br>* 3 = ETH_CLOCK_GPIO17_OUT |
| display.type | number | Specify type of display. Possible values:<br>* 0 = None (default)<br>* 1 = PCD8544 <br>* 2 = SSD1306 <br>* 3 = SH1106 |
| display.data | number | Data Pin (e.g. SDA for i2c displays) required for all displays. Use 255 for not assigned pins. |
| display.clk | number | Clock Pin (e.g. SCL for i2c displays) required for SSD1306 and SH1106. Use 255 for not assigned pins. |
| display.cs | number | Chip Select Pin required for PCD8544. Use 255 for not assigned pins. |
| display.reset | number | Reset Pin required for PCD8544, optional for all other displays. Use 255 for not assigned pins. |
| led.led0 | number | LED pin for network indication. Blinking = WLAN connected but NTP & MQTT (if enabled) disconnected. On = WLAN, NTP, MQTT connected. Off = Network not connected |
| led.led1 | number | LED pin for inverter indication. On = All inverters reachable & producing. Blinking = All inverters reachable but not producing. Off = At least one inverter is not reachable. Only inverters with polling enabled are considered. |

View File

@ -1,76 +0,0 @@
[
{
"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
}
}
]

View File

@ -1,20 +0,0 @@
[
{
"name": "CASmo-DTU",
"links": [
{"name": "Information", "url": "https://casmo.info/product-details/?product=2"}
],
"nrf24": {
"miso": 19,
"mosi": 23,
"clk": 18,
"irq": 16,
"en": 4,
"cs": 5
},
"led": {
"led0": 25,
"led1": 26
}
}
]

View File

@ -1,12 +1,6 @@
[ [
{ {
"name": "NRF, LEDs, Display", "name": "LEDs, Display",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -26,47 +20,7 @@
} }
}, },
{ {
"name": "CMT, LEDs, Display", "name": "Only Display",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"display": {
"type": 3,
"data": 21,
"clk": 22
},
"led": {
"led0": 25,
"led1": 26
}
},
{
"name": "NRF, Display",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -82,43 +36,7 @@
} }
}, },
{ {
"name": "CMT, Display", "name": "Only LEDs",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"display": {
"type": 3,
"data": 21,
"clk": 22
}
},
{
"name": "NRF, LEDs",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -133,42 +51,7 @@
} }
}, },
{ {
"name": "CMT, LEDs", "name": "No Output",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"led": {
"led0": 25,
"led1": 26
}
},
{
"name": "NRF",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-NRF-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HM-Serie-NRF-Modul/blink237542"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -177,30 +60,5 @@
"en": 4, "en": 4,
"cs": 5 "cs": 5
} }
},
{
"name": "CMT",
"links": [
{"name": "Information", "url": "https://shop.blinkyparts.com/de/OpenDTU-CMT-Deine-Auswertung-fuer-deine-Balkonsolaranlage-kompatibel-zu-Hoymiles-HMS-und-HMT-Serie-CMT-Modul/blink238342"},
{"name": "Manual DE", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_de.pdf"},
{"name": "Manual EN", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/manual/OpenDTU_Breakout_en.pdf"},
{"name": "Schematic", "url": "https://binary-kitchen.github.io/SolderingTutorial/OpenDTU_Breakout/ibom.html"}
],
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
}
} }
] ]

View File

@ -1,25 +0,0 @@
[
{
"name": "Esp32-Stick-PoE-A",
"links": [
{"name": "Information", "url": "https://github.com/allexoK/Esp32-Stick-Boards-Docs"}
],
"nrf24": {
"miso": 2,
"mosi": 15,
"clk": 14,
"irq": 34,
"en": 12,
"cs": 4
},
"eth": {
"enabled": true,
"phy_addr": 1,
"power": -1,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 3
}
}
]

View File

@ -1,74 +0,0 @@
[
{
"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
}
}
]

View File

@ -1,9 +1,6 @@
[ [
{ {
"name": "LILYGO TTGO T-Internet-POE", "name": "LILYGO TTGO T-Internet-POE",
"links": [
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
],
"nrf24": { "nrf24": {
"miso": 2, "miso": 2,
"mosi": 15, "mosi": 15,
@ -21,56 +18,5 @@
"type": 0, "type": 0,
"clk_mode": 3 "clk_mode": 3
} }
},
{
"name": "LILYGO TTGO T-Internet-POE, nrf24 direct solder",
"links": [
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
],
"nrf24": {
"miso": 12,
"mosi": 4,
"clk": 15,
"irq": 33,
"en": 14,
"cs": 2
},
"eth": {
"enabled": true,
"phy_addr": 0,
"power": -1,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 3
}
},
{
"name": "LILYGO TTGO T-Internet-POE, nrf24 direct solder, SSD1306",
"links": [
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-internet-poe"}
],
"nrf24": {
"miso": 12,
"mosi": 4,
"clk": 15,
"irq": 33,
"en": 14,
"cs": 2
},
"eth": {
"enabled": true,
"phy_addr": 0,
"power": -1,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 3
},
"display": {
"type": 2,
"data": 16,
"clk": 32
}
} }
] ]

View File

@ -1,6 +1,6 @@
[ [
{ {
"name": "NRF24", "name": "Generic NodeMCU 32",
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -10,33 +10,17 @@
"cs": 5 "cs": 5
}, },
"eth": { "eth": {
"enabled": false "enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
} }
}, },
{ {
"name": "CMT2300A", "name": "Generic NodeMCU 32 with SSD1306",
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"eth": {
"enabled": false
}
},
{
"name": "NRF24 with SSD1306",
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -46,7 +30,13 @@
"cs": 5 "cs": 5
}, },
"eth": { "eth": {
"enabled": false "enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
}, },
"display": { "display": {
"type": 2, "type": 2,
@ -55,7 +45,7 @@
} }
}, },
{ {
"name": "NRF24 with SH1106", "name": "Generic NodeMCU 32 with SH1106",
"nrf24": { "nrf24": {
"miso": 19, "miso": 19,
"mosi": 23, "mosi": 23,
@ -65,131 +55,18 @@
"cs": 5 "cs": 5
}, },
"eth": { "eth": {
"enabled": false "enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
}, },
"display": { "display": {
"type": 3, "type": 3,
"data": 21, "data": 21,
"clk": 22 "clk": 22
} }
},
{
"name": "NRF24 with SSD1309",
"nrf24": {
"miso": 19,
"mosi": 23,
"clk": 18,
"irq": 16,
"en": 4,
"cs": 5
},
"eth": {
"enabled": false
},
"display": {
"type": 4,
"data": 21,
"clk": 22
}
},
{
"name": "CMT2300A with SSD1306",
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"eth": {
"enabled": false
},
"display": {
"type": 2,
"data": 21,
"clk": 22
}
},
{
"name": "CMT2300A with SH1106",
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"eth": {
"enabled": false
},
"display": {
"type": 3,
"data": 21,
"clk": 22
}
},
{
"name": "CMT2300A with SSD1309",
"nrf24": {
"miso": -1,
"mosi": -1,
"clk": -1,
"irq": -1,
"en": -1,
"cs": -1
},
"cmt": {
"clk": 18,
"cs": 4,
"fcs": 5,
"sdio": 23,
"gpio2": 19,
"gpio3": 16
},
"eth": {
"enabled": false
},
"display": {
"type": 4,
"data": 21,
"clk": 22
}
},
{
"name": "NRF24 + CMT2300A",
"nrf24": {
"miso": 19,
"mosi": 23,
"clk": 18,
"irq": 16,
"en": 4,
"cs": 5
},
"cmt": {
"clk": 12,
"sdio": 14,
"cs": 27,
"fcs": 26,
"gpio2": -1,
"gpio3": -1
}
} }
] ]

View File

@ -1,9 +1,6 @@
[ [
{ {
"name": "Olimex ESP32-EVB", "name": "Olimex ESP32-EVB",
"links": [
{ "name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-EVB/open-source-hardware" }
],
"nrf24": { "nrf24": {
"miso": 15, "miso": 15,
"mosi": 2, "mosi": 2,

View File

@ -1,47 +0,0 @@
[
{
"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
}
}
]

View File

@ -1,9 +1,6 @@
[ [
{ {
"name": "Olimex ESP32-POE", "name": "Olimex ESP32-POE",
"links": [
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
],
"nrf24": { "nrf24": {
"miso": 15, "miso": 15,
"mosi": 2, "mosi": 2,
@ -24,9 +21,6 @@
}, },
{ {
"name": "Olimex ESP32-POE with SSD1306", "name": "Olimex ESP32-POE with SSD1306",
"links": [
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
],
"nrf24": { "nrf24": {
"miso": 15, "miso": 15,
"mosi": 2, "mosi": 2,
@ -52,9 +46,6 @@
}, },
{ {
"name": "Olimex ESP32-POE with SH1106", "name": "Olimex ESP32-POE with SH1106",
"links": [
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
],
"nrf24": { "nrf24": {
"miso": 15, "miso": 15,
"mosi": 2, "mosi": 2,
@ -73,35 +64,7 @@
"clk_mode": 3 "clk_mode": 3
}, },
"display": { "display": {
"type": 3, "type": 2,
"data": 33,
"clk": 32
}
},
{
"name": "Olimex ESP32-POE with SSD1309",
"links": [
{"name": "Datasheet", "url": "https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware"}
],
"nrf24": {
"miso": 15,
"mosi": 2,
"clk": 14,
"irq": 13,
"en": 16,
"cs": 5
},
"eth": {
"enabled": true,
"phy_addr": 0,
"power": 12,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 3
},
"display": {
"type": 4,
"data": 33, "data": 33,
"clk": 32 "clk": 32
} }

View File

@ -1,325 +0,0 @@
[
{
"name": "OpenDTU Fusion v1",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
}
},
{
"name": "OpenDTU Fusion v1 with SSD1306 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 2,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v1 with SH1106 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 3,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v2 with CMT2300A and NRF24",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
}
},
{
"name": "OpenDTU Fusion v2 with CMT2300A, NRF24 and SH1106 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 3,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v2 with CMT2300A, NRF24 and SSD1306 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"eth": {
"enabled": false,
"phy_addr": -1,
"power": -1,
"mdc": -1,
"mdio": -1,
"type": 0,
"clk_mode": 0
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 2,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v2 PoE",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"w5500": {
"mosi": 40,
"miso": 41,
"sclk": 39,
"cs": 42,
"int": 44,
"rst": 43
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 0,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v2 PoE with SH1106 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"w5500": {
"mosi": 40,
"miso": 41,
"sclk": 39,
"cs": 42,
"int": 44,
"rst": 43
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 3,
"data": 2,
"clk": 1
}
},
{
"name": "OpenDTU Fusion v2 PoE with SSD1306 Display",
"links": [
{"name": "Information", "url": "https://github.com/markusdd/OpenDTUFusionDocs"}
],
"nrf24": {
"miso": 48,
"mosi": 35,
"clk": 36,
"irq": 47,
"en": 38,
"cs": 37
},
"cmt": {
"clk": 6,
"cs": 4,
"fcs": 21,
"sdio": 5,
"gpio2": 3,
"gpio3": 8
},
"w5500": {
"mosi": 40,
"miso": 41,
"sclk": 39,
"cs": 42,
"int": 44,
"rst": 43
},
"led": {
"led0": 17,
"led1": 18
},
"display": {
"type": 2,
"data": 2,
"clk": 1
}
}
]

View File

@ -1,21 +0,0 @@
[
{
"name": "Wemos Lolin32 OLED",
"nrf24": {
"miso": 2,
"mosi": 14,
"clk": 12,
"irq": 0,
"en": 15,
"cs": 13
},
"eth": {
"enabled": false
},
"display": {
"type": 2,
"data": 5,
"clk": 4
}
}
]

View File

@ -1,9 +1,6 @@
[ [
{ {
"name": "WT32-ETH01", "name": "WT32-ETH01",
"links": [
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
],
"nrf24": { "nrf24": {
"miso": 4, "miso": 4,
"mosi": 2, "mosi": 2,
@ -21,89 +18,5 @@
"type": 0, "type": 0,
"clk_mode": 0 "clk_mode": 0
} }
},
{
"name": "WT32-ETH01 with SH1106",
"links": [
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
],
"nrf24": {
"miso": 4,
"mosi": 2,
"clk": 32,
"irq": 33,
"en": 14,
"cs": 15
},
"eth": {
"enabled": true,
"phy_addr": 1,
"power": 16,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 0
},
"display": {
"type": 3,
"data": 5,
"clk": 17
}
},
{
"name": "WT32-ETH01 with SSD1306",
"links": [
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
],
"nrf24": {
"miso": 4,
"mosi": 2,
"clk": 32,
"irq": 33,
"en": 14,
"cs": 15
},
"eth": {
"enabled": true,
"phy_addr": 1,
"power": 16,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 0
},
"display": {
"type": 2,
"data": 5,
"clk": 17
}
},
{
"name": "WT32-ETH01 with SSD1309",
"links": [
{"name": "Datasheet", "url": "http://www.wireless-tag.com/portfolio/wt32-eth01/"}
],
"nrf24": {
"miso": 4,
"mosi": 2,
"clk": 32,
"irq": 33,
"en": 14,
"cs": 15
},
"eth": {
"enabled": true,
"phy_addr": 1,
"power": 16,
"mdc": 23,
"mdio": 18,
"type": 0,
"clk_mode": 0
},
"display": {
"type": 4,
"data": 5,
"clk": 17
}
} }
] ]

View File

@ -1,3 +1,20 @@
# Display integration # Display integration
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/hardware/display/> 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.
![Config Management](screenshots/14_ConfigManagement.png)
## 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.
![Device Manager](screenshots/20_DeviceManager_Pin.png)
## Display Settings
Display settings can also be found in the "Device Manager".
![Device Manager Display](screenshots/21_DeviceManager_Display.png)

View File

@ -1,3 +1,74 @@
# MQTT Topics # MQTT Topics
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/firmware/mqtt_topics/> The base topic, as configured in the web GUI is prepended to all follwing topics.
## General topics
| Topic | R / W | Description | Value / Unit |
| --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
| dtu/ip | R | IP address of OpenDTU | IP address |
| dtu/hostname | R | Current hostname of the dtu (as set in web GUI) | |
| dtu/rssi | R | WiFi network quality | db value |
| dtu/status | R | Indicates whether OpenDTU network is reachable | online / offline |
| dtu/uptime | R | Time in seconds since startup | seconds |
## Inverter specific topics
serial will be replaced with the serial number of the inverter.
| Topic | R / W | Description | Value / Unit |
| --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
| [serial]/name | R | Name of the inverter as configured in web GUI | |
| [serial]/device/bootloaderversion | R | Bootloader version of the inverter | |
| [serial]/device/fwbuildversion | R | Firmware version of the inverter | |
| [serial]/device/fwbuilddatetime | R | Build date / time of inverter firmware | |
| [serial]/device/hwpartnumber | R | Hardware part number of the inverter | |
| [serial]/device/hwversion | R | Hardware version of the inverter | |
| [serial]/status/reachable | R | Indicates whether the inverter is reachable | 0 or 1 |
| [serial]/status/producing | R | Indicates whether the inverter is producing AC power | 0 or 1 |
| [serial]/status/last_update | R | Unix timestamp of last inverter statistics udpate | seconds since JAN 01 1970 (UTC) |
### AC channel / global specific topics
| Topic | R / W | Description | Value / Unit |
| --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
| [serial]/0/current | R | AC current in ampere | Ampere (A) |
| [serial]/0/efficiency | R | Ratio AC Power over DC Power in percent | % |
| [serial]/0/frequency | R | AC frequency in hertz | Hertz (Hz) |
| [serial]/0/power | R | AC active power in watts | Watt (W) |
| [serial]/0/powerdc | R | DC power in watts | Watt (W) |
| [serial]/0/powerfactor | R | Power factor in percent | % |
| [serial]/0/reactivepower | R | AC reactive power in VAr | VAr |
| [serial]/0/temperature | R | Temperature of inverter in degree celsius | Degree Celsius (°C) |
| [serial]/0/voltage | R | AC voltage in volt | Volt (V) |
| [serial]/0/yieldday | R | Energy converted to AC per day in watt hours | Watt hours (Wh) |
| [serial]/0/yieldtotal | R | Energy converted to AC since reset watt hours | Kilo watt hours (kWh) |
### DC input channel topics
[1-4] represents the different inputs. The amount depends on the inverter model.
| Topic | R / W | Description | Value / Unit |
| --------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
| [serial]/[1-4]/current | R | DC current of specific input in ampere | Ampere (A) |
| [serial]/[1-4]/name | R | Name of the DC input channel as configured in web GUI| |
| [serial]/[1-4]/irradiation | R | Ratio DC Power over set maximum power (in web GUI) | % |
| [serial]/[1-4]/power | R | DC power of specific input in watt | Watt (W) |
| [serial]/[1-4]/voltage | R | DC voltage of specific input in volt | Volt (V) |
| [serial]/[1-4]/yieldday | R | Energy converted to AC per day on specific input | Watt hours (Wh) |
| [serial]/[1-4]/yieldtotal | R | Energy converted to AC since reset on specific input | Kilo watt hours (kWh) |
### Inverter limit specific topics
cmd topics are used to set values. Status topics are updated from values set in the inverter.
| Topic | R / W | Description | Value / Unit |
| ----------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
| [serial]/status/limit_relative | R | Current applied production limit of the inverter | % of total possible output |
| [serial]/status/limit_absolute | R | Current applied production limit of the inverter | Watt (W) |
| [serial]/cmd/limit_persistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
| [serial]/cmd/limit_persistent_absolute | W | Set the inverter limit as a absolute value. The value will survive the night without power. The updated value will set immediatly within the inverter but show up in the web GUI and limit_relative topic after around 4 minutes. If you are using a already known inverter (known Hardware ID), the updated value will show up within a few seconds. | Watt (W) |
| [serial]/cmd/limit_nonpersistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will reset to the last persistent value at night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. The value must be published non-retained, otherwise it will be ignored! | % |
| [serial]/cmd/limit_nonpersistent_absolute | W | Set the inverter limit as a absolute value. The value will reset to the last persistent value at night without power. The updated value will set immediatly within the inverter but show up in the web GUI and limit_relative topic after around 4 minutes. If you are using a already known inverter (known Hardware ID), the updated value will show up within a few seconds. The value must be published non-retained, otherwise it will be ignored! | Watt (W) |
| [serial]/cmd/power | W | Turn the inverter on (1) or off (0) | 0 or 1 |
| [serial]/cmd/restart | W | Restarts the inverters (also resets YieldDay) | 1 |

View File

@ -1,3 +1,24 @@
# Upgrade Partition # Upgrade Partition
This documentation has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/firmware/howto/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 **ALL** provided .bin files. It is important to enter the correct target addresses.
| Address | File |
| ---------| ---------------------- |
| 0x1000 | bootloader.bin |
| 0x8000 | partitions.bin |
| 0xe000 | boot_app0.bin |
| 0x10000 | opendtu-*.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.

View File

@ -1,3 +1,564 @@
# Web API # Web API
This documentation will has been moved and can be found here: <https://tbnobody.github.io/OpenDTU-docs/firmware/web_api/> Information in JSON format can be obtained through the web API
## List of URLs
may be incomplete
| GET/POST | Auth required | URL |
| -------- | --- | -- |
| Get | yes | /api/config/get |
| Post | yes | /api/config/delete |
| Get | yes | /api/config/list |
| Post | yes | /api/config/upload |
| Get+Post | yes | /api/device/config |
| Get | no | /api/devinfo/status |
| Get+Post | yes | /api/dtu/config |
| Get | no | /api/eventlog/status?inv=inverter-serialnumber |
| Post | yes | /api/firmware/update |
| Get | yes | /api/inverter/list |
| Post | yes | /api/inverter/add |
| Post | yes | /api/inverter/del |
| Post | yes | /api/inverter/edit |
| Post | yes | /api/limit/config |
| Get | no | /api/limit/status |
| Get | no | /api/livedata/status |
| Post | yes | /api/maintenance/reboot |
| Get+Post | yes | /api/mqtt/config |
| Get | no | /api/mqtt/status |
| Get+Post | yes | /api/network/config |
| Get | no | /api/network/status |
| Get+Post | yes | /api/ntp/config |
| Get | no | /api/ntp/status |
| Get+Post | yes | /api/ntp/time |
| Get | no | /api/power/status |
| Post | yes | /api/power/config |
| Get | no | /api/prometheus/metrics |
| Get+Post | yes | /api/security/config |
| Get | yes | /api/security/authenticate |
| Get | no | /api/system/status |
## Examples of Use
### Important notes
- IP addresses and serial numbers in this examples are anonymized. Adjust to your own needs.
- The output from curl is without a linefeed at the end, so please be careful when copying the output - do not accidentally add the shell prompt directly after it.
- When POSTing config data to OpenDTU, always send all settings back, even if only one setting was changed. Sending single settings is not supported and you will receive a response `{"type":"warning","message":"Values are missing!"}`
- When POSTing, always put single quotes around the data part. Do not confuse the single quote `'` with the backtick `` ` ``. You have been warned.
- Some API calls have a single URL for GET and POST - e.g. `/api/ntp/config`
- Other API calls use e.g. `/api/limit/status` to GET data and a different URL `/api/limit/config` to POST data.
- If you want to investigate the web api communication, a good tool is [Postman](https://www.postman.com/)
- Settings API require username and password provided with Basic Authentication credentials
- If you disable the readonly access to the web API, every endpoint requires authentication
### Get information
You can "talk" to the OpenDTU with a command line tool like `curl`. The output is in plain JSON, without carriage return/linefeed and is therefore not very human readable.
#### Get current livedata
```bash
$ curl http://192.168.10.10/api/livedata/status
{"inverters":[{"serial":"11617160xxxx","name":"Meine Solaranlage","data_age":6983,"reachable":false,"producing":false,"limit_relative":0,"limit_absolute":-1,"AC":{"0":{"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"Power DC":{"v":0,"u":"W","d":1},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Frequency":{"v":0,"u":"Hz","d":2},"PowerFactor":{"v":0,"u":"","d":3},"ReactivePower":{"v":0,"u":"var","d":1},"Efficiency":{"v":0,"u":"%","d":3}}},"DC":{"0":{"name":{"u":""},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Irradiation":{"v":0,"u":"%","d":3}},"1":{"name":{"u":""},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Irradiation":{"v":0,"u":"%","d":3}},"2":{"name":{"u":""},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Irradiation":{"v":0,"u":"%","d":3}},"3":{"name":{"u":""},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3}}},"INV":{"0":{"Temperature":{"v":0,"u":"°C","d":1}}},"events":0},{"serial":"11417160xxxx","name":"test","data_age":6983,"reachable":false,"producing":false,"limit_relative":0,"limit_absolute":-1,"AC":{"0":{"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"Power DC":{"v":0,"u":"W","d":1},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Frequency":{"v":0,"u":"Hz","d":2},"PowerFactor":{"v":0,"u":"","d":3},"ReactivePower":{"v":0,"u":"var","d":1},"Efficiency":{"v":0,"u":"%","d":3}}},"DC":{"0":{"name":{"u":"test 1"},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Irradiation":{"v":0,"u":"%","d":3}},"1":{"name":{"u":"test 2"},"Power":{"v":0,"u":"W","d":1},"Voltage":{"v":0,"u":"V","d":1},"Current":{"v":0,"u":"A","d":2},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":3},"Irradiation":{"v":0,"u":"%","d":3}}},"INV":{"0":{"Temperature":{"v":0,"u":"°C","d":1}}},"events":0}],"total":{"Power":{"v":0,"u":"W","d":1},"YieldDay":{"v":0,"u":"Wh","d":0},"YieldTotal":{"v":0,"u":"kWh","d":2}},"hints":{"time_sync":false,"radio_problem":false,"default_password":false}}
```
To enhance readability (and filter information) use the JSON command line processor `jq`.
```bash
$ curl --no-progress-meter http://192.168.10.10/api/livedata/status | jq
{
"inverters": [
{
"serial": "116171603546",
"name": "Meine Solaranlage",
"data_age": 7038,
"reachable": false,
"producing": false,
"limit_relative": 0,
"limit_absolute": -1,
"AC": {
"0": {
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"Power DC": {
"v": 0,
"u": "W",
"d": 1
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Frequency": {
"v": 0,
"u": "Hz",
"d": 2
},
"PowerFactor": {
"v": 0,
"u": "",
"d": 3
},
"ReactivePower": {
"v": 0,
"u": "var",
"d": 1
},
"Efficiency": {
"v": 0,
"u": "%",
"d": 3
}
}
},
"DC": {
"0": {
"name": {
"u": ""
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Irradiation": {
"v": 0,
"u": "%",
"d": 3
}
},
"1": {
"name": {
"u": ""
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Irradiation": {
"v": 0,
"u": "%",
"d": 3
}
},
"2": {
"name": {
"u": ""
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Irradiation": {
"v": 0,
"u": "%",
"d": 3
}
},
"3": {
"name": {
"u": ""
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
}
}
},
"INV": {
"0": {
"Temperature": {
"v": 0,
"u": "°C",
"d": 1
}
}
},
"events": 0
},
{
"serial": "114171603548",
"name": "test",
"data_age": 7038,
"reachable": false,
"producing": false,
"limit_relative": 0,
"limit_absolute": -1,
"AC": {
"0": {
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"Power DC": {
"v": 0,
"u": "W",
"d": 1
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Frequency": {
"v": 0,
"u": "Hz",
"d": 2
},
"PowerFactor": {
"v": 0,
"u": "",
"d": 3
},
"ReactivePower": {
"v": 0,
"u": "var",
"d": 1
},
"Efficiency": {
"v": 0,
"u": "%",
"d": 3
}
}
},
"DC": {
"0": {
"name": {
"u": "test 1"
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Irradiation": {
"v": 0,
"u": "%",
"d": 3
}
},
"1": {
"name": {
"u": "test 2"
},
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"Voltage": {
"v": 0,
"u": "V",
"d": 1
},
"Current": {
"v": 0,
"u": "A",
"d": 2
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 3
},
"Irradiation": {
"v": 0,
"u": "%",
"d": 3
}
}
},
"INV": {
"0": {
"Temperature": {
"v": 0,
"u": "°C",
"d": 1
}
}
},
"events": 0
}
],
"total": {
"Power": {
"v": 0,
"u": "W",
"d": 1
},
"YieldDay": {
"v": 0,
"u": "Wh",
"d": 0
},
"YieldTotal": {
"v": 0,
"u": "kWh",
"d": 2
}
},
"hints": {
"time_sync": false,
"radio_problem": false,
"default_password": false
}
}
```
The eventlog can be fetched with the inverter serial number as parameter:
```bash
$ curl --no-progress-meter http://192.168.10.10/api/eventlog/status?inv=11418186xxxx | jq
{
"11418186xxxx": {
"count": 4,
"events": [
{
"message_id": 1,
"message": "Inverter start",
"start_time": 28028,
"end_time": 28028
},
{
"message_id": 209,
"message": "PV-1: No input",
"start_time": 28036,
"end_time": 0
},
{
"message_id": 2,
"message": "DTU command failed",
"start_time": 28092,
"end_time": 28092
},
{
"message_id": 207,
"message": "MPPT-A: Input undervoltage",
"start_time": 28336,
"end_time": 0
}
]
}
}
```
#### combine curl and jq
`jq` can filter specific fields from json output.
For example, filter out the current total power:
```bash
$ curl --no-progress-meter http://192.168.10.10/api/livedata/status | jq '.total | .Power.v'
140.7999878
```
#### Get information where login is required
When config data is requested, username and password have to be provided to `curl`
Username is always `admin`, the default password is `openDTU42`. The password is used for both the admin login and the Admin-mode Access Point.
```bash
$ curl --u admin:openDTU42 http://192.168.10.10/api/ntp/config
{"ntp_server":"pool.ntp.org","ntp_timezone":"CET-1CEST,M3.5.0,M10.5.0/3","ntp_timezone_descr":"Europe/Berlin"}
```
### Post information
With HTTP POST commands information can be written to the OpenDTU.
The Web API is designed to allow the web frontend in the web browser to communicate with the OpenDTU software running on the ESP32. It is not designed to be intuitive or user-friendly, so please follow the instructions here.
#### Example 1: change ntp settings
If you want to configure the ntp server setting, first fetch the information from the web API:
```bash
$ curl -u "admin:password" http://192.168.10.10/api/ntp/config
{"ntp_server":"pool.ntp.org","ntp_timezone":"CET-1CEST,M3.5.0,M10.5.0/3","ntp_timezone_descr":"Europe/Berlin"}
```
Then, second step, send your new settings. Use the text output from curl in the first step, add `data=` and enclose the whole data with single quotes.
```bash
$ curl -u "admin:password" http://192.168.10.10/api/ntp/config -d 'data={"ntp_server":"my.own.ntp.server.home","ntp_timezone":"CET-1CEST,M3.5.0,M10.5.0/3","ntp_timezone_descr":"Europe/Berlin"}'
{"type":"success","message":"Settings saved!"}
```
You will receive a json formatted response.
#### Example 2: change power limit
In the second example, I want to change the non persistent power limit of an inverter. Again, first fetch current data:
```bash
$ curl http://192.168.10.10/api/limit/status
{"11418186xxxx":{"limit_relative":100,"max_power":600,"limit_set_status":"Ok"},"11418180xxxx":{"limit_relative":100,"max_power":800,"limit_set_status":"Ok"}}
```
I see data from two configured inverters.
Now I set the relative power limit of inverter with serialnumber `11418180xxxx` to 50%.
```bash
$ curl -u "admin:password" http://192.168.10.10/api/limit/config -d 'data={"serial":"11418180xxxx", "limit_type":1, "limit_value":50}'
{"type":"success","message":"Settings saved!"}
```
Then I read again the limit status. In the first answer the status is `pending`, some seconds later it changed to `OK`.
```bash
$ curl http://192.168.10.10/api/limit/status
{"11418186xxxx":{"limit_relative":100,"max_power":600,"limit_set_status":"Ok"},"11418180xxxx":{"limit_relative":100,"max_power":800,"limit_set_status":"Pending"}}
...
$ curl http://192.168.10.10/api/limit/status
{"11418186xxxx":{"limit_relative":100,"max_power":600,"limit_set_status":"Ok"},"11418180xxxx":{"limit_relative":50,"max_power":800,"limit_set_status":"Ok"}}
```

View File

@ -1,15 +1,6 @@
# Builds using different boards # Builds using different boards
## ESP32 Dev Board ## ESP32 Dev Board
### Build by @tbnobody, jan and @marove2000
* Used build environment: generic
* Case: https://www.printables.com/de/model/441037-opendtu-breakoutboard-case
* Soldering Kit: https://shop.blinkyparts.com/en/OpenDTU-Breakoutboard-Your-evaluation-for-your-balcony-solar-system/blink237542
* Breakout board: https://github.com/marove2000/openDTU_BreakoutBoard
![](opendtu_breakoutboard.jpg)
![](thumbnail.jpg)
### Build by @Marc-- ### Build by @Marc--
* Used build environment: generic * Used build environment: generic
* Case: https://www.thingiverse.com/thing:5435911 * Case: https://www.thingiverse.com/thing:5435911

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,14 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "PinMapping.h" #include <Arduino.h>
#include <cstdint>
#include <TaskSchedulerDeclarations.h>
#include <mutex>
#include <condition_variable>
#define CONFIG_FILENAME "/config.json" #define CONFIG_FILENAME "/config.json"
#define CONFIG_VERSION 0x00011d00 // 0.1.29 // make sure to clean all after change #define CONFIG_VERSION 0x00011800 // 0.1.24 // make sure to clean all after change
#define WIFI_MAX_SSID_STRLEN 32 #define WIFI_MAX_SSID_STRLEN 32
#define WIFI_MAX_PASSWORD_STRLEN 64 #define WIFI_MAX_PASSWORD_STRLEN 64
@ -19,7 +15,6 @@
#define NTP_MAX_TIMEZONEDESCR_STRLEN 50 #define NTP_MAX_TIMEZONEDESCR_STRLEN 50
#define MQTT_MAX_HOSTNAME_STRLEN 128 #define MQTT_MAX_HOSTNAME_STRLEN 128
#define MQTT_MAX_CLIENTID_STRLEN 64
#define MQTT_MAX_USERNAME_STRLEN 64 #define MQTT_MAX_USERNAME_STRLEN 64
#define MQTT_MAX_PASSWORD_STRLEN 64 #define MQTT_MAX_PASSWORD_STRLEN 64
#define MQTT_MAX_TOPIC_STRLEN 32 #define MQTT_MAX_TOPIC_STRLEN 32
@ -28,12 +23,13 @@
#define INV_MAX_NAME_STRLEN 31 #define INV_MAX_NAME_STRLEN 31
#define INV_MAX_COUNT 10 #define INV_MAX_COUNT 10
#define INV_MAX_CHAN_COUNT 6 #define INV_MAX_CHAN_COUNT 4
#define CHAN_MAX_NAME_STRLEN 31 #define CHAN_MAX_NAME_STRLEN 31
#define DEV_MAX_MAPPING_NAME_STRLEN 63 #define DEV_MAX_MAPPING_NAME_STRLEN 63
#define LOCALE_STRLEN 2
#define JSON_BUFFER_SIZE 12288
struct CHANNEL_CONFIG_T { struct CHANNEL_CONFIG_T {
uint16_t MaxChannelPower; uint16_t MaxChannelPower;
@ -44,153 +40,85 @@ struct CHANNEL_CONFIG_T {
struct INVERTER_CONFIG_T { struct INVERTER_CONFIG_T {
uint64_t Serial; uint64_t Serial;
char Name[INV_MAX_NAME_STRLEN + 1]; char Name[INV_MAX_NAME_STRLEN + 1];
uint8_t Order;
bool Poll_Enable; bool Poll_Enable;
bool Poll_Enable_Night; bool Poll_Enable_Night;
bool Command_Enable; bool Command_Enable;
bool Command_Enable_Night; bool Command_Enable_Night;
uint8_t ReachableThreshold;
bool ZeroRuntimeDataIfUnrechable;
bool ZeroYieldDayOnMidnight;
bool ClearEventlogOnMidnight;
bool YieldDayCorrection;
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT]; CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
}; };
struct CONFIG_T { struct CONFIG_T {
struct { uint32_t Cfg_Version;
uint32_t Version; uint Cfg_SaveCount;
uint32_t SaveCount;
} Cfg;
struct { char WiFi_Ssid[WIFI_MAX_SSID_STRLEN + 1];
char Ssid[WIFI_MAX_SSID_STRLEN + 1]; char WiFi_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
char Password[WIFI_MAX_PASSWORD_STRLEN + 1]; byte WiFi_Ip[4];
uint8_t Ip[4]; byte WiFi_Netmask[4];
uint8_t Netmask[4]; byte WiFi_Gateway[4];
uint8_t Gateway[4]; byte WiFi_Dns1[4];
uint8_t Dns1[4]; byte WiFi_Dns2[4];
uint8_t Dns2[4]; bool WiFi_Dhcp;
bool Dhcp; char WiFi_Hostname[WIFI_MAX_HOSTNAME_STRLEN + 1];
char Hostname[WIFI_MAX_HOSTNAME_STRLEN + 1];
uint32_t ApTimeout;
} WiFi;
struct { char Ntp_Server[NTP_MAX_SERVER_STRLEN + 1];
bool Enabled; char Ntp_Timezone[NTP_MAX_TIMEZONE_STRLEN + 1];
} Mdns; char Ntp_TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1];
double Ntp_Longitude;
double Ntp_Latitude;
struct { bool Mqtt_Enabled;
char Server[NTP_MAX_SERVER_STRLEN + 1]; uint Mqtt_Port;
char Timezone[NTP_MAX_TIMEZONE_STRLEN + 1]; char Mqtt_Username[MQTT_MAX_USERNAME_STRLEN + 1];
char TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1]; char Mqtt_Password[MQTT_MAX_PASSWORD_STRLEN + 1];
double Longitude; char Mqtt_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
double Latitude; bool Mqtt_Retain;
uint8_t SunsetType; char Mqtt_LwtTopic[MQTT_MAX_TOPIC_STRLEN + 1];
} Ntp; char Mqtt_LwtValue_Online[MQTT_MAX_LWTVALUE_STRLEN + 1];
char Mqtt_LwtValue_Offline[MQTT_MAX_LWTVALUE_STRLEN + 1];
struct { uint32_t Mqtt_PublishInterval;
bool Enabled;
char Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1];
uint32_t Port;
char ClientId[MQTT_MAX_CLIENTID_STRLEN + 1];
char Username[MQTT_MAX_USERNAME_STRLEN + 1];
char Password[MQTT_MAX_PASSWORD_STRLEN + 1];
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
bool Retain;
uint32_t PublishInterval;
bool CleanSession;
struct {
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
char Value_Online[MQTT_MAX_LWTVALUE_STRLEN + 1];
char Value_Offline[MQTT_MAX_LWTVALUE_STRLEN + 1];
uint8_t Qos;
} Lwt;
struct {
bool Enabled;
bool Retain;
char Topic[MQTT_MAX_TOPIC_STRLEN + 1];
bool IndividualPanels;
bool Expire;
} Hass;
struct {
bool Enabled;
char RootCaCert[MQTT_MAX_CERT_STRLEN + 1];
bool CertLogin;
char ClientCert[MQTT_MAX_CERT_STRLEN + 1];
char ClientKey[MQTT_MAX_CERT_STRLEN + 1];
} Tls;
} Mqtt;
struct {
uint64_t Serial;
uint32_t PollInterval;
struct {
uint8_t PaLevel;
} Nrf;
struct {
int8_t PaLevel;
uint32_t Frequency;
uint8_t CountryMode;
} Cmt;
} Dtu;
struct {
char Password[WIFI_MAX_PASSWORD_STRLEN + 1];
bool AllowReadonly;
} Security;
struct {
bool PowerSafe;
bool ScreenSaver;
uint8_t Rotation;
uint8_t Contrast;
char Locale[LOCALE_STRLEN + 1];
struct {
uint32_t Duration;
uint8_t Mode;
} Diagram;
} Display;
struct {
uint8_t Brightness;
} Led_Single[PINMAPPING_LED_COUNT];
INVERTER_CONFIG_T Inverter[INV_MAX_COUNT]; INVERTER_CONFIG_T Inverter[INV_MAX_COUNT];
uint64_t Dtu_Serial;
uint32_t Dtu_PollInterval;
uint8_t Dtu_PaLevel;
bool Mqtt_Hass_Enabled;
bool Mqtt_Hass_Retain;
char Mqtt_Hass_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
bool Mqtt_Hass_IndividualPanels;
bool Mqtt_Tls;
char Mqtt_RootCaCert[MQTT_MAX_CERT_STRLEN + 1];
bool Mqtt_TlsCertLogin;
char Mqtt_ClientCert[MQTT_MAX_CERT_STRLEN + 1];
char Mqtt_ClientKey[MQTT_MAX_CERT_STRLEN + 1];
char Mqtt_Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1];
bool Mqtt_Hass_Expire;
char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
bool Security_AllowReadonly;
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1]; char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
bool Display_PowerSafe;
bool Display_ScreenSaver;
uint8_t Display_Rotation;
uint8_t Display_Contrast;
}; };
class ConfigurationClass { class ConfigurationClass {
public: public:
void init(Scheduler& scheduler); void init();
bool read(); bool read();
bool write(); bool write();
void migrate(); void migrate();
CONFIG_T const& get(); CONFIG_T& get();
class WriteGuard {
public:
WriteGuard();
CONFIG_T& getConfig();
~WriteGuard();
private:
std::unique_lock<std::mutex> _lock;
};
WriteGuard getWriteGuard();
INVERTER_CONFIG_T* getFreeInverterSlot(); INVERTER_CONFIG_T* getFreeInverterSlot();
INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial); INVERTER_CONFIG_T* getInverterConfig(uint64_t serial);
void deleteInverterById(const uint8_t id);
private:
void loop();
Task _loopTask;
}; };
extern ConfigurationClass Configuration; extern ConfigurationClass Configuration;

View File

@ -1,85 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
#include <mutex>
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
float getTotalAcYieldTotalEnabled();
// Sum of yield day of all enabled inverters, a inverter which is just disabled at night is also included
float getTotalAcYieldDayEnabled();
// Sum of total AC power of all enabled inverters
float getTotalAcPowerEnabled();
// Sum of total DC power of all enabled inverters
float getTotalDcPowerEnabled();
// Sum of total DC power of all enabled inverters with maxStringPower set
float getTotalDcPowerIrradiation();
// Sum of total installed irradiation of all enabled inverters
float getTotalDcIrradiationInstalled();
// Percentage (1-100) of total irradiation
float getTotalDcIrradiation();
// Amount of relevant digits for yield total
uint32_t getTotalAcYieldTotalDigits();
// Amount of relevant digits for yield total
uint32_t getTotalAcYieldDayDigits();
// Amount of relevant digits for AC power
uint32_t getTotalAcPowerDigits();
// Amount of relevant digits for DC power
uint32_t getTotalDcPowerDigits();
// True, if at least one inverter is reachable
bool getIsAtLeastOneReachable();
// True if at least one inverter is producing
bool getIsAtLeastOneProducing();
// True if at least one inverter is enabled for polling
bool getIsAtLeastOnePollEnabled();
// True if all enabled inverters are producing
bool getIsAllEnabledProducing();
// True if all enabled inverters are reachable
bool getIsAllEnabledReachable();
private:
void loop();
Task _loopTask;
std::mutex _mutex;
float _totalAcYieldTotalEnabled = 0;
float _totalAcYieldDayEnabled = 0;
float _totalAcPowerEnabled = 0;
float _totalDcPowerEnabled = 0;
float _totalDcPowerIrradiation = 0;
float _totalDcIrradiationInstalled = 0;
float _totalDcIrradiation = 0;
uint32_t _totalAcYieldTotalDigits = 0;
uint32_t _totalAcYieldDayDigits = 0;
uint32_t _totalAcPowerDigits = 0;
uint32_t _totalDcPowerDigits = 0;
bool _isAtLeastOneReachable = false;
bool _isAtLeastOneProducing = false;
bool _isAllEnabledProducing = false;
bool _isAllEnabledReachable = false;
bool _isAtLeastOnePollEnabled = false;
};
extern DatastoreClass Datastore;

View File

@ -1,34 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "Display_Graphic_Diagram.h"
#include "defaults.h" #include "defaults.h"
#include <TaskSchedulerDeclarations.h>
#include <U8g2lib.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 { enum DisplayType_t {
None, None,
PCD8544, PCD8544,
SSD1306, SSD1306,
SH1106, SH1106,
SSD1309,
ST7567_GM12864I_59N,
DisplayType_Max,
};
enum DiagramMode_t {
Off,
Small,
Fullscreen,
DisplayMode_Max,
}; };
class DisplayGraphicClass { class DisplayGraphicClass {
@ -36,52 +16,31 @@ public:
DisplayGraphicClass(); DisplayGraphicClass();
~DisplayGraphicClass(); ~DisplayGraphicClass();
void init(Scheduler& scheduler, const DisplayType_t type, const uint8_t data, const uint8_t clk, const uint8_t cs, const uint8_t reset); void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset);
void setContrast(const uint8_t contrast); void loop();
void setStatus(const bool turnOn); void setContrast(uint8_t contrast);
void setOrientation(const uint8_t rotation = DISPLAY_ROTATION); void setOrientation(uint8_t rotation = DISPLAY_ROTATION);
void setLocale(const String& locale);
void setDiagramMode(DiagramMode_t mode);
void setStartupDisplay(); void setStartupDisplay();
DisplayGraphicDiagramClass& Diagram();
bool enablePowerSafe = true; bool enablePowerSafe = true;
bool enableScreensaver = true; bool enableScreensaver = true;
private: private:
void loop(); void printText(const char* text, uint8_t line);
void printText(const char* text, const uint8_t line);
void calcLineHeights(); void calcLineHeights();
void setFont(const uint8_t line); void setFont(uint8_t line);
bool isValidDisplay();
Task _loopTask;
U8G2* _display; U8G2* _display;
DisplayGraphicDiagramClass _diagram;
bool _displayTurnedOn;
DisplayType_t _display_type = DisplayType_t::None; DisplayType_t _display_type = DisplayType_t::None;
DiagramMode_t _diagram_mode = DiagramMode_t::Off;
String _display_language = DISPLAY_LOCALE;
uint8_t _mExtra; uint8_t _mExtra;
const uint16_t _period = 1000; uint16_t _period = 1000;
const uint16_t _interval = 60000; // interval at which to power save (milliseconds) uint16_t _interval = 60000; // interval at which to power save (milliseconds)
uint32_t _lastDisplayUpdate = 0;
uint32_t _previousMillis = 0; uint32_t _previousMillis = 0;
char _fmtText[32]; char _fmtText[32];
bool _isLarge = false; bool _isLarge = false;
uint8_t _lineOffsets[5]; uint8_t _lineOffsets[5];
String _i18n_offline;
String _i18n_yield_today_kwh;
String _i18n_yield_today_wh;
String _i18n_date_format;
String _i18n_current_power_kw;
String _i18n_current_power_w;
String _i18n_yield_total_mwh;
String _i18n_yield_total_kwh;
}; };
extern DisplayGraphicClass Display; extern DisplayGraphicClass Display;

View File

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
#include <U8g2lib.h>
#include <array>
#define MAX_DATAPOINTS 128
class DisplayGraphicDiagramClass {
public:
DisplayGraphicDiagramClass();
void init(Scheduler& scheduler, U8G2* display);
void redraw(uint8_t screenSaverOffsetX, uint8_t xPos, uint8_t yPos, uint8_t width, uint8_t height, bool isFullscreen);
void updatePeriod();
private:
void averageLoop();
void dataPointLoop();
uint32_t getSecondsPerDot();
Task _averageTask;
Task _dataPointTask;
U8G2* _display = nullptr;
std::array<float, MAX_DATAPOINTS> _graphValues = {};
uint8_t _graphValuesCount = 0;
uint8_t _chartWidth = MAX_DATAPOINTS;
float _iRunningAverage = 0;
uint16_t _iRunningAverageCnt = 0;
};

View File

@ -1,35 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
#include <WString.h>
#include <list>
struct LanguageInfo_t {
String code;
String name;
String filename;
};
class I18nClass {
public:
I18nClass();
void init(Scheduler& scheduler);
std::list<LanguageInfo_t> getAvailableLanguages();
String getFilenameByLocale(const String& locale) const;
void readDisplayStrings(
const String& locale,
String& date_format,
String& offline,
String& power_w, String& power_kw,
String& yield_today_wh, String& yield_today_kwh,
String& yield_total_kwh, String& yield_total_mwh);
private:
void readLangPacks();
void readConfig(String file);
std::list<LanguageInfo_t> _availLanguages;
};
extern I18nClass I18n;

View File

@ -1,22 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <TaskSchedulerDeclarations.h>
#include <cstdint> #include <cstdint>
#define INVERTER_UPDATE_SETTINGS_INTERVAL 60000l
class InverterSettingsClass { class InverterSettingsClass {
public: public:
InverterSettingsClass(); void init();
void init(Scheduler& scheduler); void loop();
private: private:
void settingsLoop(); uint32_t _lastUpdate = 0;
void hoyLoop();
Task _settingsTask;
Task _hoyTask;
}; };
extern InverterSettingsClass InverterSettings; extern InverterSettingsClass InverterSettings;

View File

@ -2,38 +2,34 @@
#pragma once #pragma once
#include "PinMapping.h" #include "PinMapping.h"
#include <TaskSchedulerDeclarations.h>
#include <TimeoutHelper.h> #include <TimeoutHelper.h>
#define LEDSINGLE_UPDATE_INTERVAL 2000 #define LEDSINGLE_UPDATE_INTERVAL 2000
enum eLedFunction {
CONNECTED_NETWORK,
CONNECTED_MQTT,
INV_REACHABLE,
INV_PRODUCING,
};
class LedSingleClass { class LedSingleClass {
public: public:
LedSingleClass(); LedSingleClass();
void init(Scheduler& scheduler); void init();
void loop();
void turnAllOff();
void turnAllOn();
private: private:
void setLoop();
void outputLoop();
void setLed(const uint8_t ledNo, const bool ledState);
Task _setTask;
Task _outputTask;
enum class LedState_t { enum class LedState_t {
On, On,
Off, Off,
Blink, Blink,
}; };
LedState_t _ledMode[PINMAPPING_LED_COUNT]; LedState_t _ledState[PINMAPPING_LED_COUNT];
LedState_t _allMode; TimeoutHelper _updateTimeout;
bool _ledStateCurrent[PINMAPPING_LED_COUNT];
TimeoutHelper _blinkTimeout; TimeoutHelper _blinkTimeout;
uint8_t _ledActive = 0;
}; };
extern LedSingleClass LedSingle; extern LedSingleClass LedSingle;

View File

@ -4,31 +4,24 @@
#include <AsyncWebSocket.h> #include <AsyncWebSocket.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include <Stream.h> #include <Stream.h>
#include <TaskSchedulerDeclarations.h>
#include <mutex>
#define BUFFER_SIZE 500 #define BUFFER_SIZE 500
class MessageOutputClass : public Print { class MessageOutputClass : public Print {
public: public:
MessageOutputClass(); MessageOutputClass();
void init(Scheduler& scheduler); void loop();
size_t write(uint8_t c) override; size_t write(uint8_t c);
size_t write(const uint8_t* buffer, size_t size) override;
void register_ws_output(AsyncWebSocket* output); void register_ws_output(AsyncWebSocket* output);
private: private:
void loop(); AsyncWebSocket* _ws = NULL;
Task _loopTask;
AsyncWebSocket* _ws = nullptr;
char _buffer[BUFFER_SIZE]; char _buffer[BUFFER_SIZE];
uint16_t _buff_pos = 0; uint16_t _buff_pos = 0;
uint32_t _lastSend = 0; uint32_t _lastSend = 0;
bool _forceSend = false; bool _forceSend = false;
std::mutex _msgLock; SemaphoreHandle_t _lock;
}; };
extern MessageOutputClass MessageOutput; extern MessageOutputClass MessageOutput;

View File

@ -1,18 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <TaskSchedulerDeclarations.h>
#include <cstdint> #include <cstdint>
class MqttHandleDtuClass { class MqttHandleDtuClass {
public: public:
MqttHandleDtuClass(); void init();
void init(Scheduler& scheduler);
private:
void loop(); void loop();
Task _loopTask; private:
uint32_t _lastPublish;
}; };
extern MqttHandleDtuClass MqttHandleDtu; extern MqttHandleDtuClass MqttHandleDtu;

View File

@ -3,45 +3,31 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <Hoymiles.h> #include <Hoymiles.h>
#include <TaskSchedulerDeclarations.h>
// mqtt discovery device classes // mqtt discovery device classes
enum DeviceClassType { enum {
DEVICE_CLS_NONE = 0, DEVICE_CLS_NONE = 0,
DEVICE_CLS_CURRENT, DEVICE_CLS_CURRENT,
DEVICE_CLS_ENERGY, DEVICE_CLS_ENERGY,
DEVICE_CLS_PWR, DEVICE_CLS_PWR,
DEVICE_CLS_VOLTAGE, DEVICE_CLS_VOLTAGE,
DEVICE_CLS_FREQ, DEVICE_CLS_FREQ,
DEVICE_CLS_TEMP,
DEVICE_CLS_POWER_FACTOR, DEVICE_CLS_POWER_FACTOR,
DEVICE_CLS_REACTIVE_POWER, DEVICE_CLS_REACTIVE_POWER
DEVICE_CLS_CONNECTIVITY,
DEVICE_CLS_DURATION,
DEVICE_CLS_SIGNAL_STRENGTH,
DEVICE_CLS_TEMPERATURE,
DEVICE_CLS_RESTART
}; };
const char* const deviceClass_name[] = { 0, "current", "energy", "power", "voltage", "frequency", "power_factor", "reactive_power", "connectivity", "duration", "signal_strength", "temperature", "restart" }; const char* const deviceClasses[] = { 0, "current", "energy", "power", "voltage", "frequency", "temperature", "power_factor", "reactive_power" };
enum {
enum StateClassType {
STATE_CLS_NONE = 0, STATE_CLS_NONE = 0,
STATE_CLS_MEASUREMENT, STATE_CLS_MEASUREMENT,
STATE_CLS_TOTAL_INCREASING STATE_CLS_TOTAL_INCREASING
}; };
const char* const stateClass_name[] = { 0, "measurement", "total_increasing" }; const char* const stateClasses[] = { 0, "measurement", "total_increasing" };
enum CategoryType {
CATEGORY_NONE = 0,
CATEGORY_CONFIG,
CATEGORY_DIAGNOSTIC
};
const char* const category_name[] = { 0, "config", "diagnostic" };
typedef struct { typedef struct {
FieldId_t fieldId; // field id FieldId_t fieldId; // field id
DeviceClassType deviceClsId; // device class uint8_t deviceClsId; // device class
StateClassType stateClsId; // state class uint8_t stateClsId; // state class
} byteAssign_fieldDeviceClass_t; } byteAssign_fieldDeviceClass_t;
const byteAssign_fieldDeviceClass_t deviceFieldAssignment[] = { const byteAssign_fieldDeviceClass_t deviceFieldAssignment[] = {
@ -54,51 +40,28 @@ const byteAssign_fieldDeviceClass_t deviceFieldAssignment[] = {
{ FLD_IAC, DEVICE_CLS_CURRENT, STATE_CLS_MEASUREMENT }, { FLD_IAC, DEVICE_CLS_CURRENT, STATE_CLS_MEASUREMENT },
{ FLD_PAC, DEVICE_CLS_PWR, STATE_CLS_MEASUREMENT }, { FLD_PAC, DEVICE_CLS_PWR, STATE_CLS_MEASUREMENT },
{ FLD_F, DEVICE_CLS_FREQ, STATE_CLS_MEASUREMENT }, { FLD_F, DEVICE_CLS_FREQ, STATE_CLS_MEASUREMENT },
{ FLD_T, DEVICE_CLS_TEMPERATURE, STATE_CLS_MEASUREMENT }, { FLD_T, DEVICE_CLS_TEMP, STATE_CLS_MEASUREMENT },
{ FLD_PF, DEVICE_CLS_POWER_FACTOR, STATE_CLS_MEASUREMENT }, { FLD_PF, DEVICE_CLS_POWER_FACTOR, STATE_CLS_MEASUREMENT },
{ FLD_EFF, DEVICE_CLS_NONE, STATE_CLS_NONE }, { FLD_EFF, DEVICE_CLS_NONE, STATE_CLS_NONE },
{ FLD_IRR, DEVICE_CLS_NONE, STATE_CLS_NONE }, { FLD_IRR, DEVICE_CLS_NONE, STATE_CLS_NONE },
{ FLD_Q, DEVICE_CLS_REACTIVE_POWER, STATE_CLS_MEASUREMENT } { FLD_PRA, DEVICE_CLS_REACTIVE_POWER, STATE_CLS_MEASUREMENT }
}; };
#define DEVICE_CLS_ASSIGN_LIST_LEN (sizeof(deviceFieldAssignment) / sizeof(byteAssign_fieldDeviceClass_t)) #define DEVICE_CLS_ASSIGN_LIST_LEN (sizeof(deviceFieldAssignment) / sizeof(byteAssign_fieldDeviceClass_t))
class MqttHandleHassClass { class MqttHandleHassClass {
public: public:
MqttHandleHassClass(); void init();
void init(Scheduler& scheduler); void loop();
void publishConfig(); void publishConfig();
void forceUpdate(); void forceUpdate();
private: private:
void loop(); void publish(const String& subtopic, const String& payload);
static void publish(const String& subtopic, const String& payload); void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
static void publish(const String& subtopic, const JsonDocument& doc); void publishInverterButton(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* deviceClass, const char* subTopic, const char* payload);
void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, int16_t min = 1, int16_t max = 100);
static void addCommonMetadata(JsonDocument& doc, const String& unit_of_measure, const String& icon, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category); void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off);
void createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv);
// Binary Sensor
static void publishBinarySensor(JsonDocument& doc, const String& root_device, const String& unique_id_prefix, const String& name, const String& state_topic, const String& payload_on, const String& payload_off, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishDtuBinarySensor(const String& name, const String& state_topic, const String& payload_on, const String& payload_off, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const String& name, const String& state_topic, const String& payload_on, const String& payload_off, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
// Sensor
static void publishSensor(JsonDocument& doc, const String& root_device, const String& unique_id_prefix, const String& name, const String& state_topic, const String& unit_of_measure, const String& icon, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishDtuSensor(const String& name, const String& state_topic, const String& unit_of_measure, const String& icon, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishInverterSensor(std::shared_ptr<InverterAbstract> inv, const String& name, const String& state_topic, const String& unit_of_measure, const String& icon, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishInverterField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const byteAssign_fieldDeviceClass_t fieldType, const bool clear = false);
static void publishInverterButton(std::shared_ptr<InverterAbstract> inv, const String& name, const String& state_topic, const String& payload, const String& icon, const DeviceClassType device_class, const StateClassType state_class, const CategoryType category);
static void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const String& name, const String& state_topic, const String& command_topic, const int16_t min, const int16_t max, float step, const String& unit_of_measure, const String& icon, const StateClassType state_class, const CategoryType category);
static void createInverterInfo(JsonDocument& doc, std::shared_ptr<InverterAbstract> inv);
static void createDtuInfo(JsonDocument& doc);
static void createDeviceInfo(JsonDocument& doc, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device = "");
static String getDtuUniqueId();
static String getDtuUrl();
Task _loopTask;
bool _wasConnected = false; bool _wasConnected = false;
bool _updateForced = false; bool _updateForced = false;

View File

@ -3,28 +3,21 @@
#include "Configuration.h" #include "Configuration.h"
#include <Hoymiles.h> #include <Hoymiles.h>
#include <TaskSchedulerDeclarations.h>
#include <espMqttClient.h> #include <espMqttClient.h>
#include <frozen/map.h>
#include <frozen/string.h>
class MqttHandleInverterClass { class MqttHandleInverterClass {
public: public:
MqttHandleInverterClass(); void init();
void init(Scheduler& scheduler); void loop();
static String getTopic(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId); static String getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
void subscribeTopics();
void unsubscribeTopics();
private: private:
void loop(); void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
void publishField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId); void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
Task _loopTask; uint32_t _lastPublishStats[INV_MAX_COUNT];
uint32_t _lastPublish;
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };
FieldId_t _publishFields[14] = { FieldId_t _publishFields[14] = {
FLD_UDC, FLD_UDC,
@ -40,31 +33,8 @@ private:
FLD_PF, FLD_PF,
FLD_EFF, FLD_EFF,
FLD_IRR, FLD_IRR,
FLD_Q FLD_PRA
}; };
enum class Topic : unsigned {
LimitPersistentRelative,
LimitPersistentAbsolute,
LimitNonPersistentRelative,
LimitNonPersistentAbsolute,
Power,
Restart,
ResetRfStats,
};
static constexpr frozen::string _cmdtopic = "+/cmd/";
static constexpr frozen::map<frozen::string, Topic, 7> _subscriptions = {
{ "limit_persistent_relative", Topic::LimitPersistentRelative },
{ "limit_persistent_absolute", Topic::LimitPersistentAbsolute },
{ "limit_nonpersistent_relative", Topic::LimitNonPersistentRelative },
{ "limit_nonpersistent_absolute", Topic::LimitNonPersistentAbsolute },
{ "power", Topic::Power },
{ "restart", Topic::Restart },
{ "reset_rf_stats", Topic::ResetRfStats },
};
void onMqttMessage(Topic t, const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, const size_t len, const size_t index, const size_t total);
}; };
extern MqttHandleInverterClass MqttHandleInverter; extern MqttHandleInverterClass MqttHandleInverter;

View File

@ -1,17 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
class MqttHandleInverterTotalClass {
public:
MqttHandleInverterTotalClass();
void init(Scheduler& scheduler);
private:
void loop();
Task _loopTask;
};
extern MqttHandleInverterTotalClass MqttHandleInverterTotal;

View File

@ -5,7 +5,6 @@
#include <MqttSubscribeParser.h> #include <MqttSubscribeParser.h>
#include <Ticker.h> #include <Ticker.h>
#include <espMqttClient.h> #include <espMqttClient.h>
#include <mutex>
class MqttSettingsClass { class MqttSettingsClass {
public: public:
@ -14,30 +13,30 @@ public:
void performReconnect(); void performReconnect();
bool getConnected(); bool getConnected();
void publish(const String& subtopic, const String& payload); void publish(const String& subtopic, const String& payload);
void publishGeneric(const String& topic, const String& payload, const bool retain, const uint8_t qos = 0); void publishGeneric(const String& topic, const String& payload, bool retain, uint8_t qos = 0);
void subscribe(const String& topic, const uint8_t qos, const espMqttClientTypes::OnMessageCallback& cb); void subscribe(const String& topic, uint8_t qos, const espMqttClientTypes::OnMessageCallback& cb);
void unsubscribe(const String& topic); void unsubscribe(const String& topic);
String getPrefix() const; String getPrefix();
String getClientId() const;
private: private:
void NetworkEvent(network_event event); void NetworkEvent(network_event event);
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason); void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
void onMqttConnect(const bool sessionPresent); void onMqttConnect(bool sessionPresent);
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, const size_t len, const size_t index, const size_t total); void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
void performConnect(); void performConnect();
void performDisconnect(); void performDisconnect();
void createMqttClientObject(); void createMqttClientObject();
MqttClient* _mqttClient = nullptr; MqttClient* mqttClient = nullptr;
Ticker _mqttReconnectTimer; String clientId;
String willTopic;
Ticker mqttReconnectTimer;
MqttSubscribeParser _mqttSubscribeParser; MqttSubscribeParser _mqttSubscribeParser;
std::mutex _clientLock;
}; };
extern MqttSettingsClass MqttSettings; extern MqttSettingsClass MqttSettings;

View File

@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "W5500.h"
#include <DNSServer.h> #include <DNSServer.h>
#include <TaskSchedulerDeclarations.h>
#include <WiFi.h> #include <WiFi.h>
#include <vector> #include <vector>
@ -24,67 +22,59 @@ enum class network_event {
NETWORK_EVENT_MAX NETWORK_EVENT_MAX
}; };
typedef std::function<void(network_event event)> DtuNetworkEventCb; typedef std::function<void(network_event event)> NetworkEventCb;
typedef struct DtuNetworkEventCbList { typedef struct NetworkEventCbList {
DtuNetworkEventCb cb; NetworkEventCb cb;
network_event event; network_event event;
DtuNetworkEventCbList() NetworkEventCbList()
: cb(nullptr) : cb(NULL)
, event(network_event::NETWORK_UNKNOWN) , event(network_event::NETWORK_UNKNOWN)
{ {
} }
} DtuNetworkEventCbList_t; } NetworkEventCbList_t;
class NetworkSettingsClass { class NetworkSettingsClass {
public: public:
NetworkSettingsClass(); NetworkSettingsClass();
void init(Scheduler& scheduler); void init();
void loop();
void applyConfig(); void applyConfig();
void enableAdminMode(); void enableAdminMode();
String getApName() const; String getApName();
IPAddress localIP() const; IPAddress localIP();
IPAddress subnetMask() const; IPAddress subnetMask();
IPAddress gatewayIP() const; IPAddress gatewayIP();
IPAddress dnsIP(const uint8_t dns_no = 0) const; IPAddress dnsIP(uint8_t dns_no = 0);
String macAddress() const; String macAddress();
static String getHostname(); static String getHostname();
bool isConnected() const; bool isConnected();
network_mode NetworkMode() const; network_mode NetworkMode();
bool onEvent(DtuNetworkEventCb cbEvent, const network_event event = network_event::NETWORK_EVENT_MAX); bool onEvent(NetworkEventCb cbEvent, network_event event = network_event::NETWORK_EVENT_MAX);
void raiseEvent(const network_event event); void raiseEvent(network_event event);
private: private:
void loop();
void setHostname(); void setHostname();
void setStaticIp(); void setStaticIp();
void handleMDNS();
void setupMode(); void setupMode();
void NetworkEvent(const WiFiEvent_t event, WiFiEventInfo_t info); void NetworkEvent(WiFiEvent_t event);
bool adminEnabled = true;
Task _loopTask; bool forceDisconnection = false;
int adminTimeoutCounter = 0;
static constexpr byte DNS_PORT = 53; int connectTimeoutTimer = 0;
int connectRedoTimer = 0;
bool _adminEnabled = true; uint32_t lastTimerCall = 0;
bool _forceDisconnection = false; const byte DNS_PORT = 53;
uint32_t _adminTimeoutCounter = 0; IPAddress apIp;
uint32_t _adminTimeoutCounterMax = 0; IPAddress apNetmask;
uint32_t _connectTimeoutTimer = 0; std::unique_ptr<DNSServer> dnsServer;
uint32_t _connectRedoTimer = 0; bool dnsServerStatus = false;
uint32_t _lastTimerCall = 0;
IPAddress _apIp;
IPAddress _apNetmask;
std::unique_ptr<DNSServer> _dnsServer;
bool _dnsServerStatus = false;
network_mode _networkMode = network_mode::Undefined; network_mode _networkMode = network_mode::Undefined;
bool _ethConnected = false; bool _ethConnected = false;
std::vector<DtuNetworkEventCbList_t> _cbEventList; std::vector<NetworkEventCbList_t> _cbEventList;
bool _lastMdnsEnabled = false;
std::unique_ptr<W5500> _w5500;
}; };
extern NetworkSettingsClass NetworkSettings; extern NetworkSettingsClass NetworkSettings;

View File

@ -12,29 +12,12 @@
struct PinMapping_t { struct PinMapping_t {
char name[MAPPING_NAME_STRLEN + 1]; char name[MAPPING_NAME_STRLEN + 1];
int8_t nrf24_miso; int8_t nrf24_miso;
int8_t nrf24_mosi; int8_t nrf24_mosi;
int8_t nrf24_clk; int8_t nrf24_clk;
int8_t nrf24_irq; int8_t nrf24_irq;
int8_t nrf24_en; int8_t nrf24_en;
int8_t nrf24_cs; int8_t nrf24_cs;
int8_t cmt_clk;
int8_t cmt_cs;
int8_t cmt_fcs;
int8_t cmt_gpio2;
int8_t cmt_gpio3;
int8_t cmt_sdio;
int8_t w5500_mosi;
int8_t w5500_miso;
int8_t w5500_sclk;
int8_t w5500_cs;
int8_t w5500_int;
int8_t w5500_rst;
#if CONFIG_ETH_USE_ESP32_EMAC
int8_t eth_phy_addr; int8_t eth_phy_addr;
bool eth_enabled; bool eth_enabled;
int eth_power; int eth_power;
@ -42,14 +25,11 @@ struct PinMapping_t {
int eth_mdio; int eth_mdio;
eth_phy_type_t eth_type; eth_phy_type_t eth_type;
eth_clock_mode_t eth_clk_mode; eth_clock_mode_t eth_clk_mode;
#endif
uint8_t display_type; uint8_t display_type;
uint8_t display_data; uint8_t display_data;
uint8_t display_clk; uint8_t display_clk;
uint8_t display_cs; uint8_t display_cs;
uint8_t display_reset; uint8_t display_reset;
int8_t led[PINMAPPING_LED_COUNT]; int8_t led[PINMAPPING_LED_COUNT];
}; };
@ -59,19 +39,11 @@ public:
bool init(const String& deviceMapping); bool init(const String& deviceMapping);
PinMapping_t& get(); PinMapping_t& get();
bool isMappingSelected() const { return _mappingSelected; } bool isValidNrf24Config();
bool isValidEthConfig();
bool isValidNrf24Config() const;
bool isValidCmt2300Config() const;
bool isValidW5500Config() const;
#if CONFIG_ETH_USE_ESP32_EMAC
bool isValidEthConfig() const;
#endif
private: private:
PinMapping_t _pinMapping; PinMapping_t _pinMapping;
bool _mappingSelected = false;
}; };
extern PinMappingClass PinMapping; extern PinMappingClass PinMapping;

View File

@ -1,18 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
class RestartHelperClass {
public:
RestartHelperClass();
void init(Scheduler& scheduler);
void triggerRestart();
private:
void loop();
Task _rebootTask;
};
extern RestartHelperClass RestartHelper;

View File

@ -1,6 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <TaskSchedulerDeclarations.h>
extern Scheduler scheduler;

View File

@ -1,36 +1,30 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <TaskSchedulerDeclarations.h>
#include <atomic>
#include <sunset.h> #include <sunset.h>
#define SUNPOS_UPDATE_INTERVAL 60000l
class SunPositionClass { class SunPositionClass {
public: public:
SunPositionClass(); SunPositionClass();
void init(Scheduler& scheduler); void init();
void loop();
bool isDayPeriod() const; bool isDayPeriod();
bool isSunsetAvailable() const; bool sunsetTime(struct tm* info);
bool sunsetTime(struct tm* info) const; bool sunriseTime(struct tm* info);
bool sunriseTime(struct tm* info) const;
void setDoRecalc(const bool doRecalc);
private: private:
void loop();
void updateSunData(); void updateSunData();
bool checkRecalcDayChanged() const;
bool getSunTime(struct tm* info, const uint32_t offset) const;
Task _loopTask; SunSet _sun;
bool _isDayPeriod = true;
bool _isSunsetAvailable = true; uint _sunriseMinutes = 0;
uint32_t _sunriseMinutes = 0; uint _sunsetMinutes = 0;
uint32_t _sunsetMinutes = 0;
uint32_t _lastUpdate = 0;
bool _isValidInfo = false; bool _isValidInfo = false;
std::atomic_bool _doRecalc = true;
uint32_t _lastSunPositionCalculatedYMD = 0;
}; };
extern SunPositionClass SunPosition; extern SunPositionClass SunPosition;

View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <ArduinoJson.h>
#include <LittleFS.h>
#include <cstdint> #include <cstdint>
class Utils { class Utils {
@ -10,8 +8,4 @@ public:
static uint32_t getChipId(); static uint32_t getChipId();
static uint64_t generateDtuSerial(); static uint64_t generateDtuSerial();
static int getTimezoneOffset(); static int getTimezoneOffset();
static bool checkJsonAlloc(const JsonDocument& doc, const char* function, const uint16_t line);
static void removeAllFiles();
static String generateMd5FromFile(String file);
static void skipBom(File& f);
}; };

View File

@ -1,29 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <Arduino.h>
#include <driver/spi_master.h>
#include <esp_eth.h> // required for esp_eth_handle_t
#include <esp_netif.h>
#include <memory>
class W5500 {
private:
explicit W5500(spi_device_handle_t spi, gpio_num_t pin_int);
public:
W5500(const W5500&) = delete;
W5500& operator=(const W5500&) = delete;
~W5500();
static std::unique_ptr<W5500> setup(int8_t pin_mosi, int8_t pin_miso, int8_t pin_sclk, int8_t pin_cs, int8_t pin_int, int8_t pin_rst);
String macAddress();
private:
static bool connection_check_spi(spi_device_handle_t spi);
static bool connection_check_interrupt(gpio_num_t pin_int);
esp_eth_handle_t eth_handle;
esp_netif_t* eth_netif;
};

View File

@ -1,15 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "WebApi_device.h" #include "WebApi_config.h"
#include "WebApi_devinfo.h" #include "WebApi_devinfo.h"
#include "WebApi_dtu.h" #include "WebApi_dtu.h"
#include "WebApi_errors.h"
#include "WebApi_eventlog.h" #include "WebApi_eventlog.h"
#include "WebApi_file.h"
#include "WebApi_firmware.h" #include "WebApi_firmware.h"
#include "WebApi_gridprofile.h" #include "WebApi_device.h"
#include "WebApi_i18n.h"
#include "WebApi_inverter.h" #include "WebApi_inverter.h"
#include "WebApi_limit.h" #include "WebApi_limit.h"
#include "WebApi_maintenance.h" #include "WebApi_maintenance.h"
@ -23,38 +20,29 @@
#include "WebApi_webapp.h" #include "WebApi_webapp.h"
#include "WebApi_ws_console.h" #include "WebApi_ws_console.h"
#include "WebApi_ws_live.h" #include "WebApi_ws_live.h"
#include <AsyncJson.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiClass { class WebApiClass {
public: public:
WebApiClass(); WebApiClass();
void init(Scheduler& scheduler); void init();
void reload(); void loop();
static bool checkCredentials(AsyncWebServerRequest* request); static bool checkCredentials(AsyncWebServerRequest* request);
static bool checkCredentialsReadonly(AsyncWebServerRequest* request); static bool checkCredentialsReadonly(AsyncWebServerRequest* request);
static void sendTooManyRequests(AsyncWebServerRequest* request); static void sendTooManyRequests(AsyncWebServerRequest* request);
static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!");
static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document);
static uint64_t parseSerialFromRequest(AsyncWebServerRequest* request, String param_name = "inv");
static bool sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line);
private: private:
AsyncWebServer _server; AsyncWebServer _server;
AsyncEventSource _events;
WebApiConfigClass _webApiConfig;
WebApiDeviceClass _webApiDevice; WebApiDeviceClass _webApiDevice;
WebApiDevInfoClass _webApiDevInfo; WebApiDevInfoClass _webApiDevInfo;
WebApiDtuClass _webApiDtu; WebApiDtuClass _webApiDtu;
WebApiEventlogClass _webApiEventlog; WebApiEventlogClass _webApiEventlog;
WebApiFileClass _webApiFile;
WebApiFirmwareClass _webApiFirmware; WebApiFirmwareClass _webApiFirmware;
WebApiGridProfileClass _webApiGridprofile;
WebApiI18nClass _webApiI18n;
WebApiInverterClass _webApiInverter; WebApiInverterClass _webApiInverter;
WebApiLimitClass _webApiLimit; WebApiLimitClass _webApiLimit;
WebApiMaintenanceClass _webApiMaintenance; WebApiMaintenanceClass _webApiMaintenance;

19
include/WebApi_config.h Normal file
View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <ESPAsyncWebServer.h>
class WebApiConfigClass {
public:
void init(AsyncWebServer* server);
void loop();
private:
void onConfigGet(AsyncWebServerRequest* request);
void onConfigDelete(AsyncWebServerRequest* request);
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;
};

View File

@ -2,13 +2,15 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiDeviceClass { class WebApiDeviceClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onDeviceAdminGet(AsyncWebServerRequest* request); void onDeviceAdminGet(AsyncWebServerRequest* request);
void onDeviceAdminPost(AsyncWebServerRequest* request); void onDeviceAdminPost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiDevInfoClass { class WebApiDevInfoClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onDevInfoStatus(AsyncWebServerRequest* request); void onDevInfoStatus(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,17 +2,15 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiDtuClass { class WebApiDtuClass {
public: public:
WebApiDtuClass(); void init(AsyncWebServer* server);
void init(AsyncWebServer& server, Scheduler& scheduler); void loop();
private: private:
void onDtuAdminGet(AsyncWebServerRequest* request); void onDtuAdminGet(AsyncWebServerRequest* request);
void onDtuAdminPost(AsyncWebServerRequest* request); void onDtuAdminPost(AsyncWebServerRequest* request);
Task _applyDataTask; AsyncWebServer* _server;
void applyDataTaskCb();
}; };

View File

@ -5,23 +5,18 @@ enum WebApiError {
GenericBase = 1000, GenericBase = 1000,
GenericSuccess, GenericSuccess,
GenericNoValueFound, GenericNoValueFound,
GenericDataTooLarge, // not used anymore GenericDataTooLarge,
GenericParseError, GenericParseError,
GenericValueMissing, GenericValueMissing,
GenericWriteFailed,
GenericInternalServerError,
DtuBase = 2000, DtuBase = 2000,
DtuSerialZero, DtuSerialZero,
DtuPollZero, DtuPollZero,
DtuInvalidPowerLevel, DtuInvalidPowerLevel,
DtuInvalidCmtFrequency,
DtuInvalidCmtCountry,
FileBase = 3000, ConfigBase = 3000,
FileNotDeleted, ConfigNotDeleted,
FileSuccess, ConfigSuccess,
FileDeleteSuccess,
InverterBase = 4000, InverterBase = 4000,
InverterSerialZero, InverterSerialZero,
@ -32,8 +27,6 @@ enum WebApiError {
InverterInvalidMaxChannel, InverterInvalidMaxChannel,
InverterChanged, InverterChanged,
InverterDeleted, InverterDeleted,
InverterOrdered,
InverterStatsResetted,
LimitBase = 5000, LimitBase = 5000,
LimitSerialZero, LimitSerialZero,
@ -61,8 +54,6 @@ enum WebApiError {
MqttPublishInterval, MqttPublishInterval,
MqttHassTopicLength, MqttHassTopicLength,
MqttHassTopicCharacter, MqttHassTopicCharacter,
MqttLwtQos,
MqttClientIdLength,
NetworkBase = 8000, NetworkBase = 8000,
NetworkIpInvalid, NetworkIpInvalid,
@ -70,7 +61,6 @@ enum WebApiError {
NetworkGatewayInvalid, NetworkGatewayInvalid,
NetworkDns1Invalid, NetworkDns1Invalid,
NetworkDns2Invalid, NetworkDns2Invalid,
NetworkApTimeoutInvalid,
NtpBase = 9000, NtpBase = 9000,
NtpServerLength, NtpServerLength,

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiEventlogClass { class WebApiEventlogClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onEventlogStatus(AsyncWebServerRequest* request); void onEventlogStatus(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -1,18 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiFileClass {
public:
void init(AsyncWebServer& server, Scheduler& scheduler);
private:
void onFileGet(AsyncWebServerRequest* request);
void onFileDelete(AsyncWebServerRequest* request);
void onFileDeleteAll(AsyncWebServerRequest* request);
void onFileListGet(AsyncWebServerRequest* request);
void onFileUploadFinish(AsyncWebServerRequest* request);
void onFileUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
};

View File

@ -2,13 +2,15 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiFirmwareClass { class WebApiFirmwareClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onFirmwareUpdateFinish(AsyncWebServerRequest* request); void onFirmwareUpdateFinish(AsyncWebServerRequest* request);
void onFirmwareUpdateUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final); void onFirmwareUpdateUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
AsyncWebServer* _server;
}; };

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiGridProfileClass {
public:
void init(AsyncWebServer& server, Scheduler& scheduler);
private:
void onGridProfileStatus(AsyncWebServerRequest* request);
void onGridProfileRawdata(AsyncWebServerRequest* request);
};

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiI18nClass {
public:
void init(AsyncWebServer& server, Scheduler& scheduler);
private:
void onI18nLanguages(AsyncWebServerRequest* request);
void onI18nLanguage(AsyncWebServerRequest* request);
};

View File

@ -2,17 +2,17 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiInverterClass { class WebApiInverterClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onInverterList(AsyncWebServerRequest* request); void onInverterList(AsyncWebServerRequest* request);
void onInverterAdd(AsyncWebServerRequest* request); void onInverterAdd(AsyncWebServerRequest* request);
void onInverterEdit(AsyncWebServerRequest* request); void onInverterEdit(AsyncWebServerRequest* request);
void onInverterDelete(AsyncWebServerRequest* request); void onInverterDelete(AsyncWebServerRequest* request);
void onInverterOrder(AsyncWebServerRequest* request);
void onInverterStatReset(AsyncWebServerRequest* request); AsyncWebServer* _server;
}; };

View File

@ -2,13 +2,15 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiLimitClass { class WebApiLimitClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onLimitStatus(AsyncWebServerRequest* request); void onLimitStatus(AsyncWebServerRequest* request);
void onLimitPost(AsyncWebServerRequest* request); void onLimitPost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiMaintenanceClass { class WebApiMaintenanceClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onRebootPost(AsyncWebServerRequest* request); void onRebootPost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,15 +2,19 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
#define MQTT_JSON_DOC_SIZE 10240
class WebApiMqttClass { class WebApiMqttClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onMqttStatus(AsyncWebServerRequest* request); void onMqttStatus(AsyncWebServerRequest* request);
void onMqttAdminGet(AsyncWebServerRequest* request); void onMqttAdminGet(AsyncWebServerRequest* request);
void onMqttAdminPost(AsyncWebServerRequest* request); void onMqttAdminPost(AsyncWebServerRequest* request);
String getTlsCertInfo(const char* cert); String getTlsCertInfo(const char* cert);
AsyncWebServer* _server;
}; };

View File

@ -2,14 +2,16 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiNetworkClass { class WebApiNetworkClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onNetworkStatus(AsyncWebServerRequest* request); void onNetworkStatus(AsyncWebServerRequest* request);
void onNetworkAdminGet(AsyncWebServerRequest* request); void onNetworkAdminGet(AsyncWebServerRequest* request);
void onNetworkAdminPost(AsyncWebServerRequest* request); void onNetworkAdminPost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,11 +2,11 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiNtpClass { class WebApiNtpClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onNtpStatus(AsyncWebServerRequest* request); void onNtpStatus(AsyncWebServerRequest* request);
@ -14,4 +14,6 @@ private:
void onNtpAdminPost(AsyncWebServerRequest* request); void onNtpAdminPost(AsyncWebServerRequest* request);
void onNtpTimeGet(AsyncWebServerRequest* request); void onNtpTimeGet(AsyncWebServerRequest* request);
void onNtpTimePost(AsyncWebServerRequest* request); void onNtpTimePost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,13 +2,15 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiPowerClass { class WebApiPowerClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onPowerStatus(AsyncWebServerRequest* request); void onPowerStatus(AsyncWebServerRequest* request);
void onPowerPost(AsyncWebServerRequest* request); void onPowerPost(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -3,46 +3,43 @@
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Hoymiles.h> #include <Hoymiles.h>
#include <TaskSchedulerDeclarations.h>
#include <map> #include <map>
class WebApiPrometheusClass { class WebApiPrometheusClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onPrometheusMetricsGet(AsyncWebServerRequest* request); void onPrometheusMetricsGet(AsyncWebServerRequest* request);
void addField(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, const char* metricName, const char* channelName = nullptr); void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* channelName = NULL);
void addPanelInfo(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel); void addPanelInfo(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel);
enum MetricType_t { AsyncWebServer* _server;
NONE = 0,
GAUGE, enum {
COUNTER, METRIC_TYPE_NONE = 0,
METRIC_TYPE_GAUGE,
METRIC_TYPE_COUNTER,
}; };
const char* _metricTypes[3] = { 0, "gauge", "counter" }; const char* _metricTypes[3] = { 0, "gauge", "counter" };
struct publish_type_t { std::map<FieldId_t, uint8_t> _fieldMetricAssignment {
FieldId_t field; { FLD_UDC, METRIC_TYPE_GAUGE },
MetricType_t type; { FLD_IDC, METRIC_TYPE_GAUGE },
}; { FLD_PDC, METRIC_TYPE_GAUGE },
{ FLD_YD, METRIC_TYPE_COUNTER },
const publish_type_t _publishFields[14] = { { FLD_YT, METRIC_TYPE_COUNTER },
{ FLD_PAC, MetricType_t::GAUGE }, { FLD_UAC, METRIC_TYPE_GAUGE },
{ FLD_UAC, MetricType_t::GAUGE }, { FLD_IAC, METRIC_TYPE_GAUGE },
{ FLD_IAC, MetricType_t::GAUGE }, { FLD_PAC, METRIC_TYPE_GAUGE },
{ FLD_PDC, MetricType_t::GAUGE }, { FLD_F, METRIC_TYPE_GAUGE },
{ FLD_UDC, MetricType_t::GAUGE }, { FLD_T, METRIC_TYPE_GAUGE },
{ FLD_IDC, MetricType_t::GAUGE }, { FLD_PF, METRIC_TYPE_GAUGE },
{ FLD_YD, MetricType_t::COUNTER }, { FLD_EFF, METRIC_TYPE_GAUGE },
{ FLD_YT, MetricType_t::COUNTER }, { FLD_IRR, METRIC_TYPE_GAUGE },
{ FLD_F, MetricType_t::GAUGE }, { FLD_PRA, METRIC_TYPE_GAUGE }
{ FLD_T, MetricType_t::GAUGE },
{ FLD_PF, MetricType_t::GAUGE },
{ FLD_Q, MetricType_t::GAUGE },
{ FLD_EFF, MetricType_t::GAUGE },
{ FLD_IRR, MetricType_t::GAUGE },
}; };
}; };

View File

@ -2,15 +2,17 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiSecurityClass { class WebApiSecurityClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onSecurityGet(AsyncWebServerRequest* request); void onSecurityGet(AsyncWebServerRequest* request);
void onSecurityPost(AsyncWebServerRequest* request); void onSecurityPost(AsyncWebServerRequest* request);
void onAuthenticateGet(AsyncWebServerRequest* request); void onAuthenticateGet(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiSysstatusClass { class WebApiSysstatusClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void onSystemStatus(AsyncWebServerRequest* request); void onSystemStatus(AsyncWebServerRequest* request);
AsyncWebServer* _server;
}; };

View File

@ -2,12 +2,12 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiWebappClass { class WebApiWebappClass {
public: public:
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void loop();
private: private:
void responseBinaryDataWithETagCache(AsyncWebServerRequest* request, const String &contentType, const String &contentEncoding, const uint8_t *content, size_t len); AsyncWebServer* _server;
}; };

View File

@ -2,18 +2,18 @@
#pragma once #pragma once
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>
class WebApiWsConsoleClass { class WebApiWsConsoleClass {
public: public:
WebApiWsConsoleClass(); WebApiWsConsoleClass();
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void reload(); void loop();
private: private:
AsyncWebSocket _ws; void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
AsyncAuthenticationMiddleware _simpleDigestAuth;
Task _wsCleanupTask; AsyncWebServer* _server;
void wsCleanupTaskCb(); AsyncWebSocket _ws;
uint32_t _lastWsCleanup = 0;
}; };

View File

@ -1,39 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "Configuration.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Hoymiles.h> #include <Hoymiles.h>
#include <TaskSchedulerDeclarations.h>
class WebApiWsLiveClass { class WebApiWsLiveClass {
public: public:
WebApiWsLiveClass(); WebApiWsLiveClass();
void init(AsyncWebServer& server, Scheduler& scheduler); void init(AsyncWebServer* server);
void reload(); void loop();
private: private:
static void generateInverterCommonJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv); void generateJsonResponse(JsonVariant& root);
static void generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv); void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic = "");
static void generateCommonJsonResponse(JsonVariant& root); void addTotalField(JsonObject& root, String name, float value, String unit, uint8_t digits);
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 onLivedataStatus(AsyncWebServerRequest* request);
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len); void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
AsyncWebServer* _server;
AsyncWebSocket _ws; AsyncWebSocket _ws;
AsyncAuthenticationMiddleware _simpleDigestAuth;
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 }; uint32_t _lastWsPublish = 0;
uint32_t _lastInvUpdateCheck = 0;
std::mutex _mutex; uint32_t _lastWsCleanup = 0;
uint32_t _newestInverterTimestamp = 0;
Task _wsCleanupTask;
void wsCleanupTaskCb();
Task _sendDataTask;
void sendDataTaskCb();
}; };

View File

@ -1,9 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// The referenced values are generated by pio-scripts/auto_firmware_version.py
extern const char *__COMPILED_GIT_HASH__;
extern const char *__COMPILED_GIT_BRANCH__;
// extern const char *__COMPILED_DATE_TIME_UTC_STR__;

View File

@ -9,30 +9,26 @@
#define ACCESS_POINT_NAME "OpenDTU-" #define ACCESS_POINT_NAME "OpenDTU-"
#define ACCESS_POINT_PASSWORD "openDTU42" #define ACCESS_POINT_PASSWORD "openDTU42"
#define ACCESS_POINT_TIMEOUT 3
#define AUTH_USERNAME "admin" #define AUTH_USERNAME "admin"
#define SECURITY_ALLOW_READONLY true #define SECURITY_ALLOW_READONLY true
#define WIFI_RECONNECT_TIMEOUT 30 #define ADMIN_TIMEOUT 180
#define WIFI_RECONNECT_TIMEOUT 15
#define WIFI_RECONNECT_REDO_TIMEOUT 600 #define WIFI_RECONNECT_REDO_TIMEOUT 600
#define WIFI_SSID "" #define WIFI_SSID ""
#define WIFI_PASSWORD "" #define WIFI_PASSWORD ""
#define WIFI_DHCP true #define WIFI_DHCP true
#define MDNS_ENABLED false #define NTP_SERVER "pool.ntp.org"
#define NTP_SERVER_OLD "pool.ntp.org"
#define NTP_SERVER "opendtu.pool.ntp.org"
#define NTP_TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" #define NTP_TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3"
#define NTP_TIMEZONEDESCR "Europe/Berlin" #define NTP_TIMEZONEDESCR "Europe/Berlin"
#define NTP_LONGITUDE 10.4515f #define NTP_LONGITUDE 10.4515f
#define NTP_LATITUDE 51.1657f #define NTP_LATITUDE 51.1657f
#define NTP_SUNSETTYPE 1U
#define MQTT_ENABLED false #define MQTT_ENABLED false
#define MQTT_HOST "" #define MQTT_HOST ""
#define MQTT_PORT 1883U #define MQTT_PORT 1883
#define MQTT_USER "" #define MQTT_USER ""
#define MQTT_PASSWORD "" #define MQTT_PASSWORD ""
#define MQTT_TOPIC "solar/" #define MQTT_TOPIC "solar/"
@ -76,16 +72,11 @@
#define MQTT_LWT_TOPIC "dtu/status" #define MQTT_LWT_TOPIC "dtu/status"
#define MQTT_LWT_ONLINE "online" #define MQTT_LWT_ONLINE "online"
#define MQTT_LWT_OFFLINE "offline" #define MQTT_LWT_OFFLINE "offline"
#define MQTT_LWT_QOS 2U #define MQTT_PUBLISH_INTERVAL 5
#define MQTT_PUBLISH_INTERVAL 5U
#define MQTT_CLEAN_SESSION true
#define DTU_SERIAL 0x99978563412U #define DTU_SERIAL 0x99978563412
#define DTU_POLL_INTERVAL 5U #define DTU_POLL_INTERVAL 5
#define DTU_NRF_PA_LEVEL 0U #define DTU_PA_LEVEL 0
#define DTU_CMT_PA_LEVEL 0
#define DTU_CMT_FREQUENCY 865000000U
#define DTU_CMT_COUNTRY_MODE 0U
#define MQTT_HASS_ENABLED false #define MQTT_HASS_ENABLED false
#define MQTT_HASS_EXPIRE true #define MQTT_HASS_EXPIRE true
@ -97,16 +88,5 @@
#define DISPLAY_POWERSAFE true #define DISPLAY_POWERSAFE true
#define DISPLAY_SCREENSAVER true #define DISPLAY_SCREENSAVER true
#define DISPLAY_ROTATION 2U #define DISPLAY_ROTATION 2
#define DISPLAY_CONTRAST 60U #define DISPLAY_CONTRAST 60
#define DISPLAY_LOCALE "en"
#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 LANG_PACK_SUFFIX ".lang.json"

View File

@ -1,9 +0,0 @@
# Language Packs
This folder contains language packs for OpenDTU which can be uploaded to the
device using the "Config Management" function.
Select "Language Pack" in the restore section, select a `.json` file containing
your language and press "Restore". Afterwards all language selection drop down
menues contain the new language.
Create a pull to request to share your own language pack (or corrections) with the community.

View File

@ -1,696 +0,0 @@
{
"meta": {
"name": "Español",
"code": "es"
},
"display": {
"date_format": "%d/%m/%Y %H:%M",
"offline": "Apagado",
"power_w": "%.0f W",
"power_kw": "%.1f kW",
"yield_today_wh": "Hoy: %4.0f Wh",
"yield_today_kwh": "Hoy: %.1f kWh",
"yield_total_kwh": "Total: %.1f kWh",
"yield_total_mwh": "Total: %.0f kWh"
},
"webapp": {
"menu": {
"LiveView": "Vista en directo",
"Settings": "Ajustes",
"NetworkSettings": "Ajustes de Red",
"NTPSettings": "Ajustes NTP",
"MQTTSettings": "Ajustes MQTT",
"InverterSettings": "Ajustes Inversor",
"SecuritySettings": "Ajustes Seguridad",
"DTUSettings": "Ajustes DTU",
"DeviceManager": "Administrador Dispositivos",
"ConfigManagement": "Gestión configuración",
"FirmwareUpgrade": "Actualización Firmware",
"DeviceReboot": "Reinicio Dispositivo",
"Info": "Info",
"System": "Sistema",
"Network": "Red",
"NTP": "NTP",
"MQTT": "MQTT",
"Console": "Consola",
"About": "Acerca",
"Logout": "Logout",
"Login": "Login"
},
"base": {
"Loading": "Cargando...",
"Reload": "Recargar",
"Cancel": "Cancelar",
"Save": "Guardar",
"Refreshing": "Refrescando",
"Pull": "Tira hacia abajo para refrescar",
"Release": "Soltar para refrescar",
"Close": "Cerrar",
"Yes": "Yes",
"No": "No"
},
"wait": {
"NotReady": "OpenDTU is not yet ready",
"PleaseWait": "Please wait. You will be automatically redirected to the home page."
},
"Error": {
"Oops": "Oops!"
},
"localeswitcher": {
"Dark": "Oscuro",
"Light": "Claro",
"Auto": "Automático"
},
"apiresponse": {
"1001": "¡Opciones guardadas!",
"1002": "No se encontraron valores",
"1003": "Datos demasiado grandes",
"1004": "Fallo al procesar los datos",
"1005": "Faltan valores",
"1006": "Fallo en la escritura",
"2001": "¡El número de serie no puede ser cero!",
"2002": "Intervalo de Poll interval debe ser mayor que cero!",
"2003": "Configuración de potencia incorrecta!",
"2004": "La frecuencia debe estar entre {min} y {max} kHz y debe ser un múltiplo de 250 kHz!",
"2005": "Modelo desconocido! Por favor, informe el \"Modelo de pieza de hardware\" y el modelo (por ejemplo, HM-350) como un problema en <a href=\"https://github.com/tbnobody/OpenDTU/issues\" target=\"_blank\">aquí</a>.",
"3001": "No se eliminó nada",
"3002": "Configuración borrada. Reinicio en curso...",
"4001": "@:apiresponse.2001",
"4002": "El nombre debe tener entre 1 y {max} caracteres de longitud!",
"4003": "Solo se admiten {max} inversores!",
"4004": "Inversor creado!",
"4005": "ID no válido especificado",
"4006": "Cantidad de canales máxima incorrecta dada!",
"4007": "Inversor modificado!",
"4008": "Inversor eliminado!",
"4009": "Orden de inversores guardado!",
"5001": "@:apiresponse.2001",
"5002": "Límite debe estar entre 1 y {max}!",
"5003": "Tipo incorrecto especificado!",
"5004": "Inversor incorrecto especificado!",
"6001": "Reinicio desencadenado!",
"6002": "Reinicio cancelado!",
"7001": "¡El servidor MQTT debe tener entre 1 y {max} caracteres de longitud!",
"7002": "¡El nombre de usuario debe no tener más de {max} caracteres!",
"7003": "¡La contraseña debe no tener más de {max} caracteres!",
"7004": "¡El tema debe tener entre 1 y {max} caracteres de longitud!",
"7005": "¡El tema no debe contener caracteres de espacio!",
"7006": "¡El tema debe terminar con barra inclinada (/)!",
"7007": "¡El puerto debe ser un número entre 1 y 65535!",
"7008": "¡El certificado debe tener entre 1 y {max} caracteres de longitud!",
"7009": "¡El tema LWT debe tener entre 1 y {max} caracteres de longitud!",
"7010": "¡El tema LWT no debe contener caracteres de espacio!",
"7011": "¡El valor LWT en línea debe tener entre 1 y {max} caracteres de longitud!",
"7012": "¡El valor LWT fuera de línea debe tener entre 1 y {max} caracteres de longitud!",
"7013": "¡El intervalo de publicación debe ser un número entre {min} y {max}!",
"7014": "¡El tema Hass debe tener entre 1 y {max} caracteres de longitud!",
"7015": "¡El tema Hass no debe contener caracteres de espacio!",
"7016": "¡La QoS LWT no debe ser mayor que {max}!",
"7017": "Client ID must not longer then {max} characters!",
"8001": "¡La dirección IP no es válida!",
"8002": "¡La máscara de red no es válida!",
"8003": "¡El gateway no es válido!",
"8004": "¡La dirección IP del servidor DNS 1 no es válida!",
"8005": "¡La dirección IP del servidor DNS 2 no es válida!",
"8006": "¡El valor de tiempo de espera del punto de acceso administrativo es inválido!",
"9001": "¡El servidor NTP debe tener entre 1 y {max} caracteres de longitud!",
"9002": "¡La zona horaria debe tener entre 1 y {max} caracteres de longitud!",
"9003": "¡La descripción de la zona horaria debe tener entre 1 y {max} caracteres de longitud!",
"9004": "¡El año debe ser un número entre {min} y {max}!",
"9005": "¡El mes debe ser un número entre {min} y {max}!",
"9006": "¡El día debe ser un número entre {min} y {max}!",
"9007": "¡La hora debe ser un número entre {min} y {max}!",
"9008": "¡Los minutos deben ser un número entre {min} y {max}!",
"9009": "¡Los segundos deben ser un número entre {min} y {max}!",
"9010": "¡Hora actualizada!",
"10001": "¡La contraseña debe tener entre 8 y {max} caracteres de longitud!",
"10002": "¡Autenticación exitosa!",
"11001": "¡@:apiresponse.2001",
"11002": "¡@:apiresponse:5004",
"12001": "¡El perfil debe tener entre 1 y {max} caracteres de longitud!"
},
"home": {
"LiveData": "Datos en Vivo",
"SerialNumber": "Número de Serie: ",
"CurrentLimit": "Límite de Corriente: ",
"DataAge": "Edad de los Datos: ",
"Seconds": "{val} segundos",
"ShowSetInverterLimit": "Ver / Establecer Límite del Inversor",
"TurnOnOff": "Encender/Apagar el Inversor",
"ShowInverterInfo": "Ver Información del Inversor",
"ShowEventlog": "Ver Registro de Eventos",
"UnreadMessages": "mensajes sin leer",
"Loading": "@:base.Cargando",
"EventLog": "Registro de Eventos",
"InverterInfo": "Información del Inversor",
"LimitSettings": "Configuración de Límites",
"LastLimitSetStatus": "Último Estado de Configuración del Límite:",
"SetLimit": "Establecer Límite:",
"Relative": "Relativo (%)",
"Absolute": "Absoluto (W)",
"LimitHint": "<b>Consejo:</b> Si establece el límite como un valor absoluto, la visualización del valor actual solo se actualizará después de ~4 minutos.",
"SetPersistent": "Establecer Límite Permanente",
"SetNonPersistent": "Establecer Límite No Permanente",
"PowerSettings": "Configuración de Energía",
"LastPowerSetStatus": "Último Estado de Configuración de Energía:",
"TurnOn": "Encender",
"TurnOff": "Apagar",
"Restart": "Reiniciar",
"Failure": "Fallo",
"Pending": "Pendiente",
"Ok": "Aceptar",
"Unknown": "Desconocido",
"ShowGridProfile": "Ver Perfil de la Red",
"GridProfile": "Perfil de la Red",
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)",
"RadioStats": "Radio Statistics",
"TxRequest": "TX Request Count",
"RxSuccess": "RX Success",
"RxFailNothing": "RX Fail: Receive Nothing",
"RxFailPartial": "RX Fail: Receive Partial",
"RxFailCorrupt": "RX Fail: Receive Corrupt",
"TxReRequest": "TX Re-Request Fragment",
"StatsReset": "Reset Statistics",
"StatsResetting": "Resetting...",
"Rssi": "RSSI of last received packet",
"RssiHint": "HM inverters only support RSSI values < -64 dBm and > -64 dBm. In this case, -80 dbm and -30 dbm is shown.",
"dBm": "{dbm} dBm"
},
"eventlog": {
"Start": "Iniciar",
"Stop": "Parar",
"Id": "ID",
"Message": "Mensaje"
},
"devinfo": {
"NoInfo": "Sin información disponible",
"NoInfoLong": "No se ha recibido ningún dato válido del inversor hasta ahora. Todavía estamos intentando...",
"UnknownModel": "¡Modelo desconocido! Por favor, informe el \"Número de parte de hardware\" y el modelo (por ejemplo, HM-350) como un problema <a href=\"https://github.com/tbnobody/OpenDTU/issues\" target=\"_blank\">aquí</a>.",
"Serial": "Número de serie",
"ProdYear": "Año de producción",
"ProdWeek": "Semana de producción",
"Model": "Modelo",
"DetectedMaxPower": "Potencia máxima detectada",
"BootloaderVersion": "Versión del cargador de arranque",
"FirmwareVersion": "Versión del firmware",
"FirmwareBuildDate": "Fecha de construcción del firmware",
"HardwarePartNumber": "Número de parte de hardware",
"HardwareVersion": "Versión de hardware",
"SupportsPowerDistributionLogic": "'Power Distribution Logic' supported",
"Yes": "@:base.Yes",
"No": "@:base.No"
},
"gridprofile": {
"NoInfo": "@:devinfo.NoInfo",
"NoInfoLong": "@:devinfo.NoInfoLong",
"Name": "Nombre",
"Version": "Versión",
"Enabled": "@:wifistationinfo.Enabled",
"Disabled": "@:wifistationinfo.Disabled",
"GridprofileSupport": "Apoyar el desarrollo",
"GridprofileSupportLong": "Por favor, consulte <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">aquí</a> para obtener más información."
},
"systeminfo": {
"SystemInfo": "Información del sistema",
"VersionError": "Error al obtener información de la versión",
"VersionNew": "¡Nueva versión disponible! ¡Mostrar cambios!",
"VersionOk": "¡Actualizado!"
},
"firmwareinfo": {
"FirmwareInformation": "Información del firmware",
"Hostname": "Hostname",
"SdkVersion": "Versión del SDK",
"ConfigVersion": "Versión de la configuración",
"FirmwareVersion": "Versión del firmware / Hash de Git",
"PioEnv": "Entorno PIO",
"FirmwareVersionHint": "Haga clic aquí para mostrar información sobre su versión actual",
"FirmwareUpdate": "Actualización de firmware",
"FirmwareUpdateHint": "Haga clic aquí para ver las diferencias entre su versión y la última versión",
"FrmwareUpdateAllow": "Al activar la comprobación de actualización, se envía una solicitud a GitHub.com cada vez que se llama a la página para recuperar la versión actualmente disponible. Si no está de acuerdo con esto, deje esta función desactivada.",
"ResetReason0": "Razón de reinicio CPU 0",
"ResetReason1": "Razón de reinicio CPU 1",
"ConfigSaveCount": "Contador de guardado de configuración",
"Uptime": "Tiempo de actividad",
"UptimeValue": "0 días {time} | 1 día {time} | {count} días {time}"
},
"hardwareinfo": {
"HardwareInformation": "Información del hardware",
"ChipModel": "Modelo de chip",
"ChipRevision": "Revisión de chip",
"ChipCores": "Núcleos del chip",
"CpuFrequency": "Frecuencia de la CPU",
"Mhz": "MHz",
"CpuTemperature": "CPU Temperature",
"FlashSize": "Flash Memory Size"
},
"memoryinfo": {
"MemoryInformation": "Información de la memoria",
"Type": "Tipo",
"Usage": "Uso",
"Free": "Libre",
"Used": "Usado",
"Size": "Tamaño",
"Heap": "Montón",
"PsRam": "PSRAM",
"LittleFs": "LittleFs",
"Sketch": "Boceto"
},
"heapdetails": {
"HeapDetails": "Detalles del montón",
"TotalFree": "Total libre",
"LargestFreeBlock": "Bloque libre contiguo más grande",
"MaxUsage": "Uso máximo desde el inicio",
"Fragmentation": "Nivel de fragmentación"
},
"taskdetails": {
"TaskDetails": "Task Details",
"Name": "Name",
"StackFree": "Stack Free",
"Priority": "Priority",
"Task_idle0": "Idle (CPU Core 0)",
"Task_idle1": "Idle (CPU Core 1)",
"Task_wifi": "Wi-Fi",
"Task_tit": "TCP/IP",
"Task_looptask": "Arduino Main Loop",
"Task_asynctcp": "Async TCP",
"Task_mqttclient": "MQTT Client",
"Task_huaweican0": "AC Charger CAN",
"Task_pmsdm": "PowerMeter (SDM)",
"Task_pmhttpjson": "PowerMeter (HTTP+JSON)",
"Task_pmsml": "PowerMeter (Serial SML)",
"Task_pmhttpsml": "PowerMeter (HTTP+SML)"
},
"radioinfo": {
"RadioInformation": "Información de la radio",
"Status": "Estado de {module}",
"ChipStatus": "Estado del chip de {module}",
"ChipType": "Tipo de chip de {module}",
"Connected": "conectado",
"NotConnected": "no conectado",
"Configured": "configurado",
"NotConfigured": "no configurado",
"Unknown": "Desconocido"
},
"networkinfo": {
"NetworkInformation": "Información de la red"
},
"wifistationinfo": {
"WifiStationInfo": "Información de WiFi (Estación)",
"Status": "Estado",
"Enabled": "habilitado",
"Disabled": "deshabilitado",
"Ssid": "SSID",
"Bssid": "BSSID",
"Quality": "Calidad",
"Rssi": "RSSI"
},
"wifiapinfo": {
"WifiApInfo": "Información de WiFi (Punto de acceso)",
"Status": "@:wifistationinfo.Status",
"Enabled": "@:wifistationinfo.Enabled",
"Disabled": "@:wifistationinfo.Disabled",
"Ssid": "@:wifistationinfo.Ssid",
"Stations": "# Estaciones"
},
"interfacenetworkinfo": {
"NetworkInterface": "Interfaz de red ({iface})",
"Hostname": "@:firmwareinfo.Hostname",
"IpAddress": "Dirección IP",
"Netmask": "Máscara de red",
"DefaultGateway": "Puerta de enlace predeterminada",
"Dns": "DNS {num}",
"MacAddress": "Dirección MAC"
},
"interfaceapinfo": {
"NetworkInterface": "Interfaz de red (Punto de acceso)",
"IpAddress": "@:interfacenetworkinfo.IpAddress",
"MacAddress": "@:interfacenetworkinfo.MacAddress"
},
"ntpinfo": {
"NtpInformation": "Información de NTP",
"ConfigurationSummary": "Resumen de configuración",
"Server": "Servidor",
"Timezone": "Zona horaria",
"TimezoneDescription": "Descripción de la zona horaria",
"CurrentTime": "Hora actual",
"Status": "Estado",
"Synced": "sincronizado",
"NotSynced": "no sincronizado",
"LocalTime": "Hora local",
"Sunrise": "Amanecer",
"Sunset": "Atardecer",
"NotAvailable": "No disponible",
"Mode": "Modo",
"Day": "Día",
"Night": "Noche"
},
"mqttinfo": {
"MqttInformation": "Información de MQTT",
"ConfigurationSummary": "@:ntpinfo.ConfigurationSummary",
"Status": "@:ntpinfo.Status",
"Enabled": "Habilitado",
"Disabled": "Deshabilitado",
"Server": "@:ntpinfo.Server",
"Port": "Puerto",
"ClientId": "Client ID",
"Username": "Nombre de usuario",
"BaseTopic": "Tema base",
"PublishInterval": "Intervalo de publicación",
"Seconds": "{sec} segundos",
"CleanSession": "Bandera CleanSession",
"Retain": "Retener",
"Tls": "TLS",
"RootCertifcateInfo": "Información del certificado raíz de CA",
"TlsCertLogin": "Iniciar sesión con certificado TLS",
"ClientCertifcateInfo": "Información del Certificado del Cliente",
"HassSummary": "Resumen de la Configuración de Descubrimiento Automático MQTT de Home Assistant",
"Expire": "Expirar",
"IndividualPanels": "Paneles Individuales",
"RuntimeSummary": "Resumen de Tiempo de Ejecución",
"ConnectionStatus": "Estado de Conexión",
"Connected": "conectado",
"Disconnected": "desconectado"
},
"console": {
"Console": "Consola",
"VirtualDebugConsole": "Consola de Depuración Virtual",
"EnableAutoScroll": "Habilitar Desplazamiento Automático",
"ClearConsole": "Limpiar Consola",
"CopyToClipboard": "Copiar al Portapapeles"
},
"inverterchannelinfo": {
"String": "Cadena {num}",
"Phase": "Fase {num}",
"General": "General"
},
"invertertotalinfo": {
"TotalYieldTotal": "Total de Rendimiento Acumulado",
"TotalYieldDay": "Total de Rendimiento del Día",
"TotalPower": "Potencia Total"
},
"inverterchannelproperty": {
"Power": "Potencia",
"Voltage": "Voltaje",
"Current": "Corriente",
"Power DC": "Potencia DC",
"YieldDay": "Rendimiento del Día",
"YieldTotal": "Rendimiento Total",
"Frequency": "Frecuencia",
"Temperature": "Temperatura",
"PowerFactor": "Factor de Potencia",
"ReactivePower": "Potencia Reactiva",
"Efficiency": "Eficiencia",
"Irradiation": "Irradiación"
},
"maintenancereboot": {
"DeviceReboot": "Reinicio del Dispositivo",
"PerformReboot": "Realizar Reinicio",
"Reboot": "¡Reiniciar!",
"Cancel": "@:base.Cancel",
"RebootOpenDTU": "Reiniciar OpenDTU",
"RebootQuestion": "¿Realmente desea reiniciar el dispositivo?",
"RebootHint": "<b>Nota:</b> Normalmente no es necesario realizar un reinicio manual. OpenDTU realiza cualquier reinicio necesario (por ejemplo, después de una actualización de firmware) automáticamente. También se adoptan configuraciones sin reiniciar. Si necesita reiniciar debido a un error, considere informarlo en <a href=\"https://github.com/tbnobody/OpenDTU/issues\" class=\"alert-link\" target=\"_blank\">https://github.com/tbnobody/OpenDTU/issues</a>."
},
"dtuadmin": {
"DtuSettings": "Configuración de DTU",
"DtuConfiguration": "Configuración de DTU",
"Serial": "Serial",
"SerialHint": "Tanto el inversor como el DTU tienen un número de serie. El número de serie del DTU se genera aleatoriamente en el primer inicio y generalmente no es necesario cambiarlo.",
"PollInterval": "Intervalo de Sondeo",
"Seconds": "Segundos",
"NrfPaLevel": "Potencia de Transmisión NRF24",
"CmtPaLevel": "Potencia de Transmisión CMT2300A",
"NrfPaLevelHint": "Utilizado para inversores HM. Asegúrese de que su fuente de alimentación sea lo suficientemente estable antes de aumentar la potencia de transmisión.",
"CmtPaLevelHint": "Utilizado para inversores HMS/HMT. Asegúrese de que su fuente de alimentación sea lo suficientemente estable antes de aumentar la potencia de transmisión.",
"CmtCountry": "Región/País CMT2300A",
"CmtCountryHint": "Cada país tiene asignaciones de frecuencia diferentes.",
"country_0": "Europa ({min}MHz - {max}MHz)",
"country_1": "América del Norte ({min}MHz - {max}MHz)",
"country_2": "Brasil ({min}MHz - {max}MHz)",
"CmtFrequency": "Frecuencia CMT2300A",
"CmtFrequencyHint": "¡Asegúrese de utilizar solo frecuencias permitidas en el país respectivo! Después de un cambio de frecuencia, puede tardar hasta 15 minutos en establecer una conexión.",
"CmtFrequencyWarning": "La frecuencia seleccionada está fuera del rango permitido en su región/país seleccionado. Asegúrese de que esta selección no infrinja ninguna regulación local.",
"MHz": "{mhz} MHz",
"dBm": "{dbm} dBm",
"Min": "Mínimo ({db} dBm)",
"Low": "Bajo ({db} dBm)",
"High": "Alto ({db} dBm)",
"Max": "Máximo ({db} dBm)"
},
"securityadmin": {
"SecuritySettings": "Configuración de Seguridad",
"AdminPassword": "Contraseña de Administrador",
"Password": "Contraseña",
"RepeatPassword": "Repetir Contraseña",
"PasswordHint": "<b>Consejo:</b> La contraseña de administrador se utiliza para acceder a esta interfaz web (usuario 'admin'), pero también para conectarse al dispositivo cuando está en modo AP. Debe tener 8 a 64 caracteres.",
"Permissions": "Permisos",
"ReadOnly": "Permitir acceso de solo lectura a la interfaz web sin contraseña"
},
"ntpadmin": {
"NtpSettings": "Configuración de NTP",
"NtpConfiguration": "Configuración de NTP",
"TimeServer": "Servidor de Tiempo",
"TimeServerHint": "El valor predeterminado es adecuado siempre que OpenDTU tenga acceso directo a Internet.",
"Timezone": "Zona Horaria",
"TimezoneConfig": "Configuración de Zona Horaria",
"LocationConfiguration": "Configuración de Ubicación",
"Longitude": "Longitud",
"Latitude": "Latitud",
"SunSetType": "Tipo de Atardecer",
"SunSetTypeHint": "Afecta al cálculo día/noche. Puede tardar hasta un minuto en aplicarse el nuevo tipo.",
"OFFICIAL": "Amanecer estándar (90.8°)",
"NAUTICAL": "Amanecer náutico (102°)",
"CIVIL": "Amanecer civil (96°)",
"ASTONOMICAL": "Amanecer astronómico (108°)",
"ManualTimeSynchronization": "Sincronización Manual del Tiempo",
"CurrentOpenDtuTime": "Hora Actual de OpenDTU",
"CurrentLocalTime": "Hora Local Actual",
"SynchronizeTime": "Sincronizar Tiempo",
"SynchronizeTimeHint": "<b>Consejo:</b> Puede utilizar la sincronización manual del tiempo para establecer la hora actual de OpenDTU si no hay un servidor NTP disponible. Pero tenga en cuenta que en caso de un ciclo de energía, se perderá la hora. Además, tenga en cuenta que la precisión del tiempo se verá gravemente afectada, ya que no se puede resincronizar regularmente y el microcontrolador ESP32 no tiene un reloj en tiempo real."
},
"networkadmin": {
"NetworkSettings": "Configuración de Red",
"WifiConfiguration": "Configuración de WiFi",
"WifiSsid": "SSID de WiFi",
"WifiPassword": "Contraseña de WiFi",
"Hostname": "Nombre de Host",
"HostnameHint": "<b>Consejo:</b> El texto <span class=\"font-monospace\">%06X</span> se remplazará con los últimos 6 dígitos del ChipID de ESP en formato hexadecimal.",
"EnableDhcp": "Habilitar DHCP",
"StaticIpConfiguration": "Configuración de IP Estática",
"IpAddress": "Dirección IP",
"Netmask": "Máscara de Red",
"DefaultGateway": "Puerta de Enlace Predeterminada",
"Dns": "Servidor DNS {num}",
"AdminAp": "Configuración de WiFi (Punto de Acceso de Administrador)",
"ApTimeout": "Tiempo de espera del Punto de Acceso",
"ApTimeoutHint": "Tiempo que se mantiene abierto el Punto de Acceso. Un valor de 0 significa infinito.",
"Minutes": "minutos",
"EnableMdns": "Habilitar mDNS",
"MdnsSettings": "Configuración de mDNS"
},
"mqttadmin": {
"MqttSettings": "Configuración de MQTT",
"MqttConfiguration": "Configuración de MQTT",
"EnableMqtt": "Habilitar MQTT",
"EnableHass": "Habilitar Descubrimiento Automático MQTT de Home Assistant",
"MqttBrokerParameter": "Parámetros del Broker MQTT",
"Hostname": "Nombre de Host",
"HostnameHint": "Nombre de host o dirección IP",
"Port": "Puerto",
"ClientId": "Client ID",
"Username": "Nombre de Usuario",
"UsernameHint": "Nombre de usuario, dejar vacío para conexión anónima",
"Password": "Contraseña",
"PasswordHint": "Contraseña, dejar vacío para conexión anónima",
"BaseTopic": "Tema Base",
"BaseTopicHint": "Tema base, se antepondrá a todos los temas publicados (por ejemplo, inverter/)",
"PublishInterval": "Intervalo de Publicación",
"Seconds": "segundos",
"CleanSession": "Habilitar Bandera CleanSession",
"EnableRetain": "Habilitar Bandera Retain",
"EnableTls": "Habilitar TLS",
"RootCa": "Certificado Raíz CA (predeterminado Letsencrypt)",
"TlsCertLoginEnable": "Habilitar Inicio de Sesión con Certificado TLS",
"ClientCert": "Certificado del Cliente TLS",
"ClientKey": "Clave del Cliente TLS",
"LwtParameters": "Parámetros de LWT",
"LwtTopic": "Tema de LWT",
"LwtTopicHint": "Tema de LWT, se añadirá al tema base",
"LwtOnline": "Mensaje de LWT en línea",
"LwtOnlineHint": "Mensaje que se publicará en el tema de LWT cuando esté en línea",
"LwtOffline": "Mensaje de LWT fuera de línea",
"LwtOfflineHint": "Mensaje que se publicará en el tema de LWT cuando esté fuera de línea",
"LwtQos": "QoS (Calidad de Servicio)",
"QOS0": "0 (Como máximo una vez)",
"QOS1": "1 (Al menos una vez)",
"QOS2": "2 (Exactamente una vez)",
"HassParameters": "Parámetros de Descubrimiento Automático MQTT de Home Assistant",
"HassPrefixTopic": "Tema de Prefijo",
"HassPrefixTopicHint": "El prefijo para el tema de descubrimiento",
"HassRetain": "Habilitar Bandera Retain",
"HassExpire": "Habilitar Expiración",
"HassIndividual": "Paneles Individuales"
},
"inverteradmin": {
"InverterSettings": "Configuración del Inversor",
"AddInverter": "Agregar un nuevo Inversor",
"Serial": "Serial",
"Name": "Nombre",
"Add": "Agregar",
"AddHint": "<b>Consejo:</b> Puede configurar parámetros adicionales después de haber creado el inversor. Use el ícono de lápiz en la lista de inversores.",
"InverterList": "Lista de Inversores",
"Status": "Estado",
"Send": "Enviar",
"Receive": "Recibir",
"StatusHint": "<b>Consejo:</b> El inversor se alimenta con su entrada de CC. Si no hay sol, el inversor está apagado. Aún se pueden enviar solicitudes.",
"Type": "Tipo",
"Action": "Acción",
"SaveOrder": "Guardar orden",
"DeleteInverter": "Eliminar inversor",
"EditInverter": "Editar inversor",
"General": "General",
"String": "Cadena",
"Advanced": "Avanzado",
"InverterSerial": "Serial del Inversor:",
"InverterName": "Nombre del Inversor:",
"InverterNameHint": "Aquí puede especificar un nombre personalizado para su inversor.",
"InverterStatus": "Recibir / Enviar",
"PollEnable": "Sondear datos del inversor",
"PollEnableNight": "Sondear datos del inversor por la noche",
"CommandEnable": "Enviar comandos",
"CommandEnableNight": "Enviar comandos por la noche",
"StringName": "Nombre de cadena {num}:",
"StringNameHint": "Aquí puede especificar un nombre personalizado para el puerto respectivo de su inversor.",
"StringMaxPower": "Potencia máxima de cadena {num}:",
"StringMaxPowerHint": "Ingrese la potencia máxima de los paneles solares conectados.",
"StringYtOffset": "Compensación total de rendimiento de cadena {num}:",
"StringYtOffsetHint": "Esta compensación se aplica al valor total de rendimiento leído del inversor. Esto se puede usar para ajustar el rendimiento total del inversor a cero si se utiliza un inversor usado. Pero aún puede intentar sondear datos.",
"InverterHint": "*) Ingrese W<sub>p</sub> del canal para calcular la irradiación.",
"ReachableThreshold": "Umbral de Alcanzabilidad",
"ReachableThresholdHint": "Define cuántas solicitudes se permiten fallar hasta que el inversor se considere no alcanzable.",
"ZeroRuntime": "Datos de tiempo cero",
"ZeroRuntimeHint": "Datos de tiempo cero (sin datos de rendimiento) si el inversor se vuelve inalcanzable.",
"ZeroDay": "Rendimiento diario cero a medianoche",
"ZeroDayHint": "Esto solo funciona si el inversor es inalcanzable. Si se leen datos del inversor, se usarán sus valores. (El reinicio solo ocurre en el ciclo de energía)",
"ClearEventlog": "Clear Eventlog at midnight",
"Cancel": "@:base.Cancel",
"Save": "@:base.Save",
"DeleteMsg": "¿Está seguro de que desea eliminar el inversor \"{name}\" con número de serie {serial}?",
"Delete": "Eliminar",
"YieldDayCorrection": "Corrección de Rendimiento Diario",
"YieldDayCorrectionHint": "Sumar el rendimiento diario incluso si el inversor se reinicia. El valor se restablecerá a medianoche"
},
"fileadmin": {
"ConfigManagement": "Gestión de Configuración",
"BackupHeader": "Copia de seguridad: Copia de Seguridad del Archivo de Configuración",
"BackupConfig": "Copia de seguridad del archivo de configuración",
"Backup": "Copia de seguridad",
"Restore": "Restaurar",
"NoFileSelected": "Ningún archivo seleccionado",
"RestoreHeader": "Restaurar: Restaurar el Archivo de Configuración",
"Back": "Atrás",
"UploadSuccess": "Carga Exitosa",
"RestoreHint": "<b>Nota:</b> Esta operación reemplaza el archivo de configuración con la configuración restaurada y reinicia OpenDTU para aplicar todas las configuraciones.",
"ResetHeader": "Inicializar: Realizar Restablecimiento de Fábrica",
"FactoryResetButton": "Restaurar Configuraciones Predeterminadas de Fábrica",
"ResetHint": "<b>Nota:</b> Haga clic en Restaurar Configuraciones Predeterminadas de Fábrica para restaurar e inicializar las configuraciones predeterminadas de fábrica y reiniciar.",
"FactoryReset": "Restablecimiento de Fábrica",
"ResetMsg": "¿Está seguro de que desea eliminar la configuración actual y restablecer todas las configuraciones a sus valores predeterminados de fábrica?",
"ResetConfirm": "Restablecimiento de Fábrica",
"Cancel": "@:base.Cancel",
"InvalidJson": "JSON file is formatted incorrectly.",
"InvalidJsonContent": "JSON file has the wrong content."
},
"login": {
"Login": "Iniciar Sesión",
"SystemLogin": "Inicio de Sesión en el Sistema",
"Username": "Nombre de Usuario",
"UsernameRequired": "Se requiere el nombre de usuario",
"Password": "Contraseña",
"PasswordRequired": "Se requiere la contraseña",
"LoginButton": "Iniciar Sesión"
},
"firmwareupgrade": {
"FirmwareUpgrade": "Actualización de Firmware",
"Loading": "@:base.Loading",
"OtaError": "Error OTA",
"Back": "Atrás",
"Retry": "Reintentar",
"OtaStatus": "Estado OTA",
"OtaSuccess": "La carga de firmware fue exitosa. El dispositivo se reinició automáticamente. Cuando el dispositivo vuelva a ser accesible, la interfaz se recargará automáticamente.",
"FirmwareUpload": "Carga de Firmware",
"UploadProgress": "Progreso de Carga"
},
"about": {
"AboutOpendtu": "Acerca de OpenDTU",
"Documentation": "Documentation",
"DocumentationBody": "The firmware and hardware documentation can be found here: <a href=\"https://www.opendtu.solar\" target=\"_blank\">https://www.opendtu.solar</a>",
"ProjectOrigin": "Origen del Proyecto",
"ProjectOriginBody1": "Este proyecto se inició a partir de <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">esta discusión. (Mikrocontroller.net)</a>",
"ProjectOriginBody2": "El protocolo de Hoymiles fue descifrado mediante los esfuerzos voluntarios de muchos participantes. OpenDTU, entre otros, se desarrolló basado en este trabajo. El proyecto está bajo una Licencia de Código Abierto (<a href=\"https://www.gnu.de/documents/gpl-2.0.de.html\" target=\"_blank\">Licencia Pública General de GNU versión 2</a>).",
"ProjectOriginBody3": "El software se desarrolló según nuestro mejor conocimiento y creencia. Sin embargo, no se acepta ninguna responsabilidad por un mal funcionamiento o pérdida de garantía del inversor.",
"ProjectOriginBody4": "OpenDTU está disponible de forma gratuita. Si pagaste dinero por el software, probablemente te estafaron.",
"NewsUpdates": "Noticias y Actualizaciones",
"NewsUpdatesBody": "Las nuevas actualizaciones se pueden encontrar en Github: <a href=\"https://github.com/tbnobody/OpenDTU\" target=\"_blank\">https://github.com/tbnobody/OpenDTU</a>",
"ErrorReporting": "Reporte de Errores",
"ErrorReportingBody": "Por favor, informa problemas utilizando la función proporcionada por <a href=\"https://github.com/tbnobody/OpenDTU/issues\" target=\"_blank\">Github</a>",
"Discussion": "Discusión",
"DiscussionBody": "Discute con nosotros en <a href=\"https://discord.gg/WzhxEY62mB\" target=\"_blank\">Discord</a> o <a href=\"https://github.com/tbnobody/OpenDTU/discussions\" target=\"_blank\">Github</a>"
},
"hints": {
"RadioProblem": "No se pudo conectar a un módulo de radio configurado. Por favor, verifica la conexión.",
"TimeSync": "El reloj aún no ha sido sincronizado. Sin un reloj correctamente ajustado, no se realizan solicitudes al inversor. Esto es normal poco después del inicio. Sin embargo, después de un tiempo de ejecución más largo (>1 minuto), indica que el servidor NTP no es accesible.",
"TimeSyncLink": "Por favor, verifica la configuración de tu hora.",
"DefaultPassword": "Estás utilizando la contraseña predeterminada para la interfaz web y el punto de acceso de emergencia. Esto potencialmente es inseguro.",
"DefaultPasswordLink": "Por favor, cambia la contraseña.",
"PinMappingIssue": "You are using a generic firmware image, but have not yet uploaded a file with device profiles (<code>pin_mapping.json</code>) or have not selected a profile defined there. Please refer to the <a href=\"https://opendtu.solar/firmware/device_profiles/\" target=\"_blank\" class=\"alert-link\">documentation</a> for details."
},
"deviceadmin": {
"DeviceManager": "Administrador de Dispositivos",
"ParseError": "Error de análisis en 'pin_mapping.json': {error}",
"PinAssignment": "Configuración de Conexión",
"SelectedProfile": "Perfil Seleccionado",
"DefaultProfile": "(Configuraciones predeterminadas)",
"ProfileHint": "Tu dispositivo puede dejar de responder si seleccionas un perfil incompatible. En este caso, debes realizar una eliminación a través de la interfaz serial.",
"Display": "Pantalla",
"PowerSafe": "Habilitar Ahorro de Energía",
"PowerSafeHint": "Apaga la pantalla si no hay un inversor produciendo.",
"Screensaver": "Habilitar Protector de Pantalla",
"ScreensaverHint": "Mueve la pantalla un poco en cada actualización para evitar el quemado. (Útil especialmente para pantallas OLED)",
"DiagramMode": "Modo de Diagrama",
"off": "Apagar",
"small": "Pequeño",
"fullscreen": "Pantalla Completa",
"DiagramDuration": "Duración del Diagrama",
"DiagramDurationHint": "El período de tiempo que se muestra en el diagrama.",
"Seconds": "Segundos",
"Contrast": "Contraste ({contrast})",
"Rotation": "Rotación",
"rot0": "Sin rotación",
"rot90": "Rotación de 90 grados",
"rot180": "Rotación de 180 grados",
"rot270": "Rotación de 270 grados",
"DisplayLanguage": "Idioma de la Pantalla",
"en": "Inglés",
"de": "Alemán",
"fr": "Francés",
"Leds": "LEDs",
"EqualBrightness": "Brillo Equitativo",
"LedBrightness": "Brillo del LED {led} ({brightness})"
},
"pininfo": {
"Category": "Categoría",
"Name": "Nombre",
"Number": "Número",
"ValueSelected": "Seleccionado",
"ValueActive": "Activo"
},
"inputserial": {
"format_hoymiles": "Hoymiles serial number format",
"format_converted": "Already converted serial number",
"format_herf_valid": "E-Star HERF format (will be saved converted): {serial}",
"format_herf_invalid": "E-Star HERF format: Invalid checksum",
"format_unknown": "Unknown format"
}
}
}

View File

@ -1,696 +0,0 @@
{
"meta": {
"name": "Italiano",
"code": "it"
},
"display": {
"date_format": "%d/%m/%Y %H:%M",
"offline": "Offline",
"power_w": "%.0f W",
"power_kw": "%.1f kW",
"yield_today_wh": "oggi: %4.0f Wh",
"yield_today_kwh": "oggi: %.1f kWh",
"yield_total_kwh": "totale: %.1f kWh",
"yield_total_mwh": "totale: %.0f kWh"
},
"webapp": {
"menu": {
"LiveView": "Dati in tempo reale",
"Settings": "Impostazioni",
"NetworkSettings": "Impostazioni di rete",
"NTPSettings": "Impostazioni NTP",
"MQTTSettings": "Impostazioni MQTT",
"InverterSettings": "Impostazioni Inverter",
"SecuritySettings": "Impostazioni di Sicurezza",
"DTUSettings": "Impostazioni DTU",
"DeviceManager": "Gestione Dispositivi",
"ConfigManagement": "Gestione Configurazione",
"FirmwareUpgrade": "Aggiornamento Firmware",
"DeviceReboot": "Riavvio DTU",
"Info": "Info",
"System": "Sistema",
"Network": "Rete",
"NTP": "NTP",
"MQTT": "MQTT",
"Console": "Console",
"About": "Informazioni DTU",
"Logout": "Esci",
"Login": "Login"
},
"base": {
"Loading": "Caricamento...",
"Reload": "Ricarica",
"Cancel": "Cancella",
"Save": "Salva",
"Refreshing": "Aggiorna",
"Pull": "Trascina in basso per aggiornare",
"Release": "Rilascia per aggiornare",
"Close": "Chiudi",
"Yes": "Yes",
"No": "No"
},
"wait": {
"NotReady": "OpenDTU is not yet ready",
"PleaseWait": "Please wait. You will be automatically redirected to the home page."
},
"Error": {
"Oops": "Oops!"
},
"localeswitcher": {
"Dark": "Scuro",
"Light": "Chiaro",
"Auto": "Automatico"
},
"apiresponse": {
"1001": "Settings saved!",
"1002": "No values found!",
"1003": "Data too large!",
"1004": "Failed to parse data!",
"1005": "Values are missing!",
"1006": "Write failed!",
"2001": "Serial cannot be zero!",
"2002": "Poll interval must be greater zero!",
"2003": "Invalid power level setting!",
"2004": "The frequency must be set between {min} and {max} kHz and must be a multiple of 250kHz!",
"2005": "Invalid country selection!",
"3001": "Not deleted anything!",
"3002": "Configuration resettet. Rebooting now...",
"4001": "@:apiresponse.2001",
"4002": "Name must between 1 and {max} characters long!",
"4003": "Only {max} inverters are supported!",
"4004": "Inverter created!",
"4005": "Invalid ID specified!",
"4006": "Invalid amount of max channel setting given!",
"4007": "Inverter changed!",
"4008": "Inverter deleted!",
"4009": "Inverter order saved!",
"5001": "@:apiresponse.2001",
"5002": "Limit must between 1 and {max}!",
"5003": "Invalid type specified!",
"5004": "Invalid inverter specified!",
"6001": "Reboot triggered!",
"6002": "Reboot cancled!",
"7001": "MQTT Server must between 1 and {max} characters long!",
"7002": "Username must not longer then {max} characters!",
"7003": "Password must not longer then {max} characters!",
"7004": "Topic must not longer then {max} characters!",
"7005": "Topic must not contain space characters!",
"7006": "Topic must end with slash (/)!",
"7007": "Port must be a number between 1 and 65535!",
"7008": "Certificate must not longer then {max} characters!",
"7009": "LWT topic must not longer then {max} characters!",
"7010": "LWT topic must not contain space characters!",
"7011": "LWT online value must not longer then {max} characters!",
"7012": "LWT offline value must not longer then {max} characters!",
"7013": "Publish interval must be a number between {min} and {max}!",
"7014": "Hass topic must not longer then {max} characters!",
"7015": "Hass topic must not contain space characters!",
"7016": "LWT QOS must not greater then {max}!",
"7017": "Client ID must not longer then {max} characters!",
"8001": "IP address is invalid!",
"8002": "Netmask is invalid!",
"8003": "Gateway is invalid!",
"8004": "DNS Server IP 1 is invalid!",
"8005": "DNS Server IP 2 is invalid!",
"8006": "Administrative AccessPoint Timeout value is invalid",
"9001": "NTP Server must between 1 and {max} characters long!",
"9002": "Timezone must between 1 and {max} characters long!",
"9003": "Timezone description must between 1 and {max} characters long!",
"9004": "Year must be a number between {min} and {max}!",
"9005": "Month must be a number between {min} and {max}!",
"9006": "Day must be a number between {min} and {max}!",
"9007": "Hour must be a number between {min} and {max}!",
"9008": "Minute must be a number between {min} and {max}!",
"9009": "Second must be a number between {min} and {max}!",
"9010": "Time updated!",
"10001": "Password must between 8 and {max} characters long!",
"10002": "Authentication successful!",
"11001": "@:apiresponse.2001",
"11002": "@:apiresponse:5004",
"12001": "Profil must between 1 and {max} characters long!"
},
"home": {
"LiveData": "Dati in tempo reale",
"SerialNumber": "Numero seriale: ",
"CurrentLimit": "Limite attuale: ",
"DataAge": "Aggiornamento Dati: ",
"Seconds": "{val} secondi",
"ShowSetInverterLimit": "Mostra / Imposta Limite di Potenza",
"TurnOnOff": "Accendi/Spegni Inverter",
"ShowInverterInfo": "Mostra info Inverter",
"ShowEventlog": "Mostra Log Eventi",
"UnreadMessages": "msg non letti",
"Loading": "@:base.Loading",
"EventLog": "Log Eventi",
"InverterInfo": "Info Inverter",
"LimitSettings": "Impostazioni Limite Potenza",
"LastLimitSetStatus": "Stato ultimo limite impostato:",
"SetLimit": "Imposta Limite a:",
"Relative": "Percentuale (%)",
"Absolute": "Assoluto (W)",
"LimitHint": "<b>Nota:</b> Se imposti il limite assoluto, il valore sul display sarà aggiornato dopo circa 4 minuti.",
"SetPersistent": "Imposta Limite in Modo Persistente",
"SetNonPersistent": "Imposta Limite Temporaneamente",
"PowerSettings": "Impostazioni Potenza",
"LastPowerSetStatus": "Ultimo Stato dell'Inverter:",
"TurnOn": "Accendi Inverter",
"TurnOff": "Spegni Inverter",
"Restart": "Riavvia Inverter",
"Failure": "Fallito",
"Pending": "In Attesa",
"Ok": "Ok",
"Unknown": "Sconosciuto",
"ShowGridProfile": "Mostra Settaggi Inverter",
"GridProfile": "Settaggi Inverter",
"LoadingInverter": "In attesa dei dati... (puo' richiedere fino a 10 secondi)",
"RadioStats": "Radio Statistics",
"TxRequest": "TX Request Count",
"RxSuccess": "RX Success",
"RxFailNothing": "RX Fail: Receive Nothing",
"RxFailPartial": "RX Fail: Receive Partial",
"RxFailCorrupt": "RX Fail: Receive Corrupt",
"TxReRequest": "TX Re-Request Fragment",
"StatsReset": "Reset Statistics",
"StatsResetting": "Resetting...",
"Rssi": "RSSI of last received packet",
"RssiHint": "HM inverters only support RSSI values < -64 dBm and > -64 dBm. In this case, -80 dbm and -30 dbm is shown.",
"dBm": "{dbm} dBm"
},
"eventlog": {
"Start": "Inizio",
"Stop": "Fine",
"Id": "ID",
"Message": "Messaggio"
},
"devinfo": {
"NoInfo": "Informazioni non disponibili",
"NoInfoLong": "Ancora nessuna informazione dall'inverter. Sto riprovando...",
"UnknownModel": "Modello sconosciuto! Per favore fornisci \"Hardware Part Number\" ed il modello (esempio HM-350) in una Issue su <a href=\"https://github.com/tbnobody/OpenDTU/issues\" target=\"_blank\">GitHub</a>.",
"Serial": "Seriale",
"ProdYear": "Produzione Annua",
"ProdWeek": "Produzione Settimanale",
"Model": "Modello",
"DetectedMaxPower": "Rilevata potenza massima",
"BootloaderVersion": "Versione Bootloader",
"FirmwareVersion": "Versione Firmware",
"FirmwareBuildDate": "Data Firmware",
"HardwarePartNumber": "Hardware Part Number",
"HardwareVersion": "Hardware Version",
"SupportsPowerDistributionLogic": "'Power Distribution Logic' supported",
"Yes": "@:base.Yes",
"No": "@:base.No"
},
"gridprofile": {
"NoInfo": "@:devinfo.NoInfo",
"NoInfoLong": "@:devinfo.NoInfoLong",
"Name": "Nome",
"Version": "Versione",
"Enabled": "@:wifistationinfo.Enabled",
"Disabled": "@:wifistationinfo.Disabled",
"GridprofileSupport": "Supporto sviluppatori",
"GridprofileSupportLong": "Clicca <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">qui</a> per ulteriori informazioni."
},
"systeminfo": {
"SystemInfo": "Info Sistema",
"VersionError": "Errore ricezione della versione",
"VersionNew": "Nuova versione disponibile! Mostra aggiornamenti!",
"VersionOk": "Già aggiornato!"
},
"firmwareinfo": {
"FirmwareInformation": "Info Firmware",
"Hostname": "Hostname",
"SdkVersion": "SDK Version",
"ConfigVersion": "Config Version",
"FirmwareVersion": "Firmware Version / Git Hash",
"PioEnv": "PIO Environment",
"FirmwareVersionHint": "Click here to show information about your current version",
"FirmwareUpdate": "Firmware Update",
"FirmwareUpdateHint": "Click here to view the changes between your version and the latest version",
"FrmwareUpdateAllow": "By activating the update check, a request is sent to GitHub.com each time the page is called up to retrieve the currently available version. If you do not agree with this, leave this function deactivated.",
"ResetReason0": "Reset Reason CPU 0",
"ResetReason1": "Reset Reason CPU 1",
"ConfigSaveCount": "Config save count",
"Uptime": "Uptime",
"UptimeValue": "0 days {time} | 1 day {time} | {count} days {time}"
},
"hardwareinfo": {
"HardwareInformation": "Info Hardware",
"ChipModel": "Chip Model",
"ChipRevision": "Chip Revision",
"ChipCores": "Chip Cores",
"CpuFrequency": "CPU Frequency",
"Mhz": "MHz",
"CpuTemperature": "CPU Temperature",
"FlashSize": "Flash Memory Size"
},
"memoryinfo": {
"MemoryInformation": "Info Memoria",
"Type": "Tipo",
"Usage": "Uso",
"Free": "Libera",
"Used": "Usata",
"Size": "Dimensione",
"Heap": "Heap",
"PsRam": "PSRAM",
"LittleFs": "LittleFs",
"Sketch": "Sketch"
},
"heapdetails": {
"HeapDetails": "Dettagli memoria Heap",
"TotalFree": "Libera totale",
"LargestFreeBlock": "Blocco contiguo libero più grande",
"MaxUsage": "Massima utilizzata dall'avvio",
"Fragmentation": "Livello frammentazione"
},
"taskdetails": {
"TaskDetails": "Task Details",
"Name": "Name",
"StackFree": "Stack Free",
"Priority": "Priority",
"Task_idle0": "Idle (CPU Core 0)",
"Task_idle1": "Idle (CPU Core 1)",
"Task_wifi": "Wi-Fi",
"Task_tit": "TCP/IP",
"Task_looptask": "Arduino Main Loop",
"Task_asynctcp": "Async TCP",
"Task_mqttclient": "MQTT Client",
"Task_huaweican0": "AC Charger CAN",
"Task_pmsdm": "PowerMeter (SDM)",
"Task_pmhttpjson": "PowerMeter (HTTP+JSON)",
"Task_pmsml": "PowerMeter (Serial SML)",
"Task_pmhttpsml": "PowerMeter (HTTP+SML)"
},
"radioinfo": {
"RadioInformation": "Info Transceiver Radio",
"Status": "{module} Stato",
"ChipStatus": "{module} Chip Stato",
"ChipType": "{module} Chip Tipo",
"Connected": "connesso",
"NotConnected": "non connesso",
"Configured": "configurato",
"NotConfigured": "no configurato",
"Unknown": "Sconosciuto"
},
"networkinfo": {
"NetworkInformation": "Informazioni Rete"
},
"wifistationinfo": {
"WifiStationInfo": "Info WiFi (Station)",
"Status": "Stato",
"Enabled": "abilitato",
"Disabled": "disabilitato",
"Ssid": "SSID",
"Bssid": "BSSID",
"Quality": "Qualità",
"Rssi": "RSSI"
},
"wifiapinfo": {
"WifiApInfo": "Info WiFi (Access Point)",
"Status": "@:wifistationinfo.Status",
"Enabled": "@:wifistationinfo.Enabled",
"Disabled": "@:wifistationinfo.Disabled",
"Ssid": "@:wifistationinfo.Ssid",
"Stations": "Numero Stazioni"
},
"interfacenetworkinfo": {
"NetworkInterface": "Interfaccia di Rete ({iface})",
"Hostname": "@:firmwareinfo.Hostname",
"IpAddress": "Indirizzo IP",
"Netmask": "Netmask",
"DefaultGateway": "Gateway",
"Dns": "DNS {num}",
"MacAddress": "Indirizzo MAC"
},
"interfaceapinfo": {
"NetworkInterface": "Interfaccia di Rete (Access Point)",
"IpAddress": "@:interfacenetworkinfo.IpAddress",
"MacAddress": "@:interfacenetworkinfo.MacAddress"
},
"ntpinfo": {
"NtpInformation": "Informazioni NTP",
"ConfigurationSummary": "Riepilogo Configurazione",
"Server": "Server",
"Timezone": "Timezone",
"TimezoneDescription": "Descrizione Timezone",
"CurrentTime": "Data/Ora attuale",
"Status": "Stato",
"Synced": "sincronizzata",
"NotSynced": "non sincronizzata",
"LocalTime": "Ora Locale",
"Sunrise": "Alba",
"Sunset": "Tramonto",
"NotAvailable": "Non Disponibile",
"Mode": "Modalità",
"Day": "Giorno",
"Night": "Notte"
},
"mqttinfo": {
"MqttInformation": "Informazioni MQTT",
"ConfigurationSummary": "@:ntpinfo.ConfigurationSummary",
"Status": "@:ntpinfo.Status",
"Enabled": "Abilitato",
"Disabled": "Disabilitato",
"Server": "@:ntpinfo.Server",
"Port": "Porta",
"ClientId": "Client ID",
"Username": "Username",
"BaseTopic": "Topic Base",
"PublishInterval": "Intervallo Publish",
"Seconds": "{sec} secondi",
"CleanSession": "CleanSession",
"Retain": "Retain",
"Tls": "TLS",
"RootCertifcateInfo": "Info Certificato Root CA",
"TlsCertLogin": "Entra con Certificato TLS",
"ClientCertifcateInfo": "Info Certificato Client",
"HassSummary": "Riepilogo Configurazione Home Assistant MQTT Auto Discovery",
"Expire": "Scade",
"IndividualPanels": "Pannello Individuale",
"RuntimeSummary": "Riepilogo Runtime",
"ConnectionStatus": "Stato Connessione",
"Connected": "connesso",
"Disconnected": "disconnesso"
},
"console": {
"Console": "Console",
"VirtualDebugConsole": "Virtual Debug Console",
"EnableAutoScroll": "Abilita AutoScroll",
"ClearConsole": "Pulisci Console",
"CopyToClipboard": "Copia nella clipboard"
},
"inverterchannelinfo": {
"String": "Stringa {num}",
"Phase": "Fase {num}",
"General": "Generale"
},
"invertertotalinfo": {
"TotalYieldTotal": "Totale Energia",
"TotalYieldDay": "Energia Giornaliera",
"TotalPower": "Potenza Totale"
},
"inverterchannelproperty": {
"Power": "Potenza",
"Voltage": "Tensione",
"Current": "Corrente",
"Power DC": "PotenzaDC",
"YieldDay": "EnergiaOggi",
"YieldTotal": "EnergiaTotale",
"Frequency": "Frequenza",
"Temperature": "Temperatura",
"PowerFactor": "FattorePotenza",
"ReactivePower": "PotenzaReattiva",
"Efficiency": "Efficienza",
"Irradiation": "Irragiamento"
},
"maintenancereboot": {
"DeviceReboot": "Riavvio DTU",
"PerformReboot": "Fai il riavvio",
"Reboot": "Riavvio!",
"Cancel": "@:base.Cancel",
"RebootOpenDTU": "Riavvio OpenDTU",
"RebootQuestion": "Vuoi veramente riavvia il DTU?",
"RebootHint": "<b>Nota:</b> Normalmente non serve riavviare OpenDTU, in quanto esegue automaticamente il ravvio quando necessario (ad esempio dopo aggiornamento firmware). Modifiche alla configurazione vengono apprese subito, senza richiedere riavvio. Se devi riavviare a causa di un errore, ti preghiamo di segnalarcelo cliccando su <a href=\"https://github.com/tbnobody/OpenDTU/issues\" class=\"alert-link\" target=\"_blank\">https://github.com/tbnobody/OpenDTU/issues</a>."
},
"dtuadmin": {
"DtuSettings": "Impostazioni DTU",
"DtuConfiguration": "Configurazione DTU",
"Serial": "Seriale",
"SerialHint": "Sia il DTU che l'inverter hanno un numero seriale. Il numero seriale del DTU è generato casualmente al primo avvio e normalmente non serve modificarlo.",
"PollInterval": "Intervallo Interrogazione",
"Seconds": "Secondi",
"NrfPaLevel": "Potenza Trasmettitore NRF24",
"CmtPaLevel": "Potenza Trasmettitore CMT2300A",
"NrfPaLevelHint": "Usato per inverter HM. Considera che aumentando la potenza aumentano il consumo di corrente.",
"CmtPaLevelHint": "Usato per inverter HMS/HMT. Considera che aumentando la potenza aumentano il consumo di corrente.",
"CmtCountry": "CMT2300A Zona/Paese",
"CmtCountryHint": "Ogni zona ha una differente allocazione di frequenze utilizzabili.",
"country_0": "Europa ({min}MHz - {max}MHz)",
"country_1": "Nord America ({min}MHz - {max}MHz)",
"country_2": "Brasile ({min}MHz - {max}MHz)",
"CmtFrequency": "Frequenza CMT2300A",
"CmtFrequencyHint": "Fai attenzione ad usare solo frequenze ammesse nel tuo Paese! Dopo la modifica frequenza, servono fino a 15 minuti affinché la connessione si ristabilisca.",
"CmtFrequencyWarning": "La frequenza selezionata è fuori dal range selezionato dal tuo Paese. Verifica che la frequenza selezionata non violi le normative del tuo Paese.",
"MHz": "{mhz} MHz",
"dBm": "{dbm} dBm",
"Min": "Minima ({db} dBm)",
"Low": "Bassa ({db} dBm)",
"High": "Alta ({db} dBm)",
"Max": "Massima ({db} dBm)"
},
"securityadmin": {
"SecuritySettings": "Impostazioni di Sicurezza",
"AdminPassword": "Password Admin",
"Password": "Password",
"RepeatPassword": "Ripeti Password",
"PasswordHint": "<b>Nota:</b> La password di amministrazione viene utilizzata non solo per accedere a questa interfaccia web (con user 'admin'), ma anche per connettersi al dispositivo in modalità AP. Deve avere da 8 a 64 caratteri.",
"Permissions": "Permessi",
"ReadOnly": "Permetti accessi web in sola lettura senza richiedere la password"
},
"ntpadmin": {
"NtpSettings": "Impostazioni NTP (Data / Ora)",
"NtpConfiguration": "Configurazione NTP",
"TimeServer": "Server NTP",
"TimeServerHint": "Puoi lasciare il valore di default, nel caso in cui OpenDTU abbia accesso ad internet.",
"Timezone": "Timezone",
"TimezoneConfig": "Timezone Config",
"LocationConfiguration": "Configurazione Posizione",
"Longitude": "Longitudine",
"Latitude": "Latitudine",
"SunSetType": "Tipo di Alba",
"SunSetTypeHint": "Influenza il calcolo dell'ora di Alba/Tramonto. Dopo la conferma, è richiesto fino ad un minuto perché la modifica venga applicata.",
"OFFICIAL": "Standard dawn (90.8°)",
"NAUTICAL": "Nautical dawn (102°)",
"CIVIL": "Civil dawn (96°)",
"ASTONOMICAL": "Astronomical dawn (108°)",
"ManualTimeSynchronization": "Sincronizzazione Manuale Data/Ora",
"CurrentOpenDtuTime": "Ora OpenDTU attuale",
"CurrentLocalTime": "Ora Locale attuale",
"SynchronizeTime": "Sincronizza Data/Ora",
"SynchronizeTimeHint": "<b>Nota:</b> Puoi usare la sincronizzazione manuale per impostare Data/Ora nel caso che non sia disponibile un server NTP. In questo caso la data/ora viene persa in caso di mancata alimentazione. Inoltre, con la sincronizzazione manuale ci sarà una progressiva deriva della Data/Ora in quanto l'ESP32 non ha un Real Time Clock interno."
},
"networkadmin": {
"NetworkSettings": "Impostazioni di Rete",
"WifiConfiguration": "Configurazione WiFi",
"WifiSsid": "WiFi SSID",
"WifiPassword": "WiFi Password",
"Hostname": "Hostname",
"HostnameHint": "<b>Nota:</b> Il testo <span class=\"font-monospace\">%06X</span> sarà rimpiazzato con le ultime 6 cifre del ChipID dell'ESP32 in formato esadecimale.",
"EnableDhcp": "Abilita DHCP",
"StaticIpConfiguration": "Configurazione IP Statico",
"IpAddress": "Indirizzo IP",
"Netmask": "Netmask",
"DefaultGateway": "Default Gateway",
"Dns": "DNS Server {num}",
"AdminAp": "Configurazione WiFi (Admin AccessPoint)",
"ApTimeout": "Timeout AccessPoint",
"ApTimeoutHint": "Tempo in cui la modalità AccessPoint rimarrà attiva. 0=per sempre.",
"Minutes": "minuti",
"EnableMdns": "Abilita mDNS",
"MdnsSettings": "Configurazione mDNS"
},
"mqttadmin": {
"MqttSettings": "Impostazioni MQTT",
"MqttConfiguration": "Configurazione MQTT",
"EnableMqtt": "Abilita MQTT",
"EnableHass": "Abilita Home Assistant MQTT Auto Discovery",
"MqttBrokerParameter": "Parametri Broker MQTT",
"Hostname": "Hostname",
"HostnameHint": "Hostname o Indirizzo IP",
"Port": "Porta",
"ClientId": "Client ID",
"Username": "Username",
"UsernameHint": "Username, lascia vuoto per connessione anonima",
"Password": "Password",
"PasswordHint": "Password, lascia vuota per connessione anonima",
"BaseTopic": "Topic Base",
"BaseTopicHint": "Topic Base, prefisso da aggiungere (ad esempio inverter/)",
"PublishInterval": "Intervallo pubblicazione",
"Seconds": "secondi",
"CleanSession": "Abilita CleanSession",
"EnableRetain": "Abilita Retain",
"EnableTls": "Abilita TLS",
"RootCa": "CA-Root-Certificate (default Letsencrypt)",
"TlsCertLoginEnable": "Abilita Login con certificato TLS",
"ClientCert": "TLS Client-Certificate",
"ClientKey": "TLS Client-Key",
"LwtParameters": "Parametri LWT",
"LwtTopic": "Topic LWT",
"LwtTopicHint": "Topic LWT, da aggiungere al Topic Base",
"LwtOnline": "Messaggio 'Online0 LWT",
"LwtOnlineHint": "Messaggio pubblicato quando online",
"LwtOffline": "Messaggio 'Offline' LWT",
"LwtOfflineHint": "Messaggio che sarà pubblicato quando offline",
"LwtQos": "QoS (Quality of Service)",
"QOS0": "0 (Al massimo una volta)",
"QOS1": "1 (Almeno una volta)",
"QOS2": "2 (Esattamente una volta)",
"HassParameters": "Parametri Home Assistant MQTT Auto Discovery",
"HassPrefixTopic": "Prefisso Topic",
"HassPrefixTopicHint": "Prefisso per Topic autodiscovery",
"HassRetain": "Abilita Retain",
"HassExpire": "Abilita Scadenza",
"HassIndividual": "Pannelli Individuale"
},
"inverteradmin": {
"InverterSettings": "Impostazioni Inverter",
"AddInverter": "Aggiungi nuovo Inverter",
"Serial": "Seriale",
"Name": "Nome",
"Add": "Aggiungi",
"AddHint": "<b>Nota:</b> Potrai aggiungere ulteriori parametri dopo aver creato l'inverter, cliccando sull'icona 'Matita' nella lista inverter.",
"InverterList": "Lista Inverter",
"Status": "Stato",
"Send": "Invia",
"Receive": "Riceve",
"StatusHint": "<b>Nota:</b> L'inverter viene alimentato dal fotovoltaico. Durante la notte, l'inverter risulterà spento. Le richieste potranno comunque essere trasmesse.",
"Type": "Tipo",
"Action": "Azione",
"SaveOrder": "Salva ordine",
"DeleteInverter": "Rimuovi inverter",
"EditInverter": "Modifica inverter",
"General": "Generale",
"String": "Stringa",
"Advanced": "Avanzate",
"InverterSerial": "Seriale Inverter:",
"InverterName": "Nome Inverter:",
"InverterNameHint": "Puoi specificare un nome qualsiasi da assegnare all'inverter.",
"InverterStatus": "Riceve / Invia",
"PollEnable": "Interroga inverter",
"PollEnableNight": "Interroga inverter di notte",
"CommandEnable": "Invia comandi",
"CommandEnableNight": "Invia comandi di notte",
"StringName": "Nome stringa {num}:",
"StringNameHint": "Qui puoi specificare un nome qualsiasi per la porta dell'inverter o per il pannello fotovoltaico collegato.",
"StringMaxPower": "Massima potenza stringa {num}:",
"StringMaxPowerHint": "Inserisci la potenza massima associata ai panelli fotovoltaici collegati a questa stringa.",
"StringYtOffset": "Offset Energia totale per la stringa {num}:",
"StringYtOffsetHint": "Questo offset viene utilizzato per azzerare il contatore qualora venga usato un inverter usato.",
"InverterHint": "*) Inserisci la potenza W<sub>p</sub> dei pannelli fotovoltaici collegati alla stringa: servirà per calcolare l'irragiamento.",
"ReachableThreshold": "Reachable Threshold",
"ReachableThresholdHint": "Definisce il numero di richieste fallite prima che l'inverter sia considerato irraggiungibile.",
"ZeroRuntime": "Azzera dati in tempo reale",
"ZeroRuntimeHint": "Azzera i dati in tempo reale (tranne l'Energia) se l'inverter diventa irraggiunbile.",
"ZeroDay": "Azzera dati energia alla mezzanotte",
"ZeroDayHint": "Questo vale se l'inverter risulta irraggiungibile. Se l'inverter risponde anche di notte, verranno mostrati i suoi valori. (Il Reset si verifica al riavvio)",
"ClearEventlog": "Clear Eventlog at midnight",
"Cancel": "@:base.Cancel",
"Save": "@:base.Save",
"DeleteMsg": "Sicuro di voler rimuovere l'inverter \"{name}\" con numero seriale {serial}?",
"Delete": "Rimuovi",
"YieldDayCorrection": "Correzione energia giornaliera",
"YieldDayCorrectionHint": "Aggiungi questo valore all'energia giornaliera se l'inverter è stato riavviato. Questo valore sarò resettato a mezzanotte"
},
"fileadmin": {
"ConfigManagement": "Configurazione Gestione",
"BackupHeader": "Backup: Configurazione File Backup",
"BackupConfig": "Esegui il backup del file",
"Backup": "Backup",
"Restore": "Ripristina",
"NoFileSelected": "Nessun file selezionato",
"RestoreHeader": "Ripristina: Ripristina File Configurazione",
"Back": "Indietro",
"UploadSuccess": "Invio File con successo",
"RestoreHint": "<b>Nota:</b> questa operazione rimpiazza la configurazione con quella contenuta nel file, e poi riavvia automaticamente OpenDTU per applicare la nuova configurazione.",
"ResetHeader": "Inizializza: Esegui il Factory Reset",
"FactoryResetButton": "Ripristina Configurazione Factory-Default",
"ResetHint": "<b>Nota:</b> Clicca 'Ripristina Configurazione Factory-Default' per stabilire le impostazioni di fabbrica e riavviare automaticamente OpenDTU.",
"FactoryReset": "Factory Reset",
"ResetMsg": "Sei sicuro di voler cancellare la configurazione attuale e applicare la configurazione di fabbrica?",
"ResetConfirm": "Factory Reset!",
"Cancel": "@:base.Cancel",
"InvalidJson": "JSON file is formatted incorrectly.",
"InvalidJsonContent": "JSON file has the wrong content."
},
"login": {
"Login": "Login",
"SystemLogin": "System Login",
"Username": "Username",
"UsernameRequired": "Inserisci Username",
"Password": "Password",
"PasswordRequired": "Inserisci Password",
"LoginButton": "Login"
},
"firmwareupgrade": {
"FirmwareUpgrade": "Aggiornamento Firmware",
"Loading": "@:base.Loading",
"OtaError": "Errore aggiornamento OTA",
"Back": "Indietro",
"Retry": "Riprova",
"OtaStatus": "Stato OTA",
"OtaSuccess": "Aggiornamento firmware eseguito con successo. Il dispositivo si riavvierà automaticamente. Quando sarà nuovamente disponibile, l'interfacca sarà ricaricata automaticamente.",
"FirmwareUpload": "Invia Firmware",
"UploadProgress": "Upload in corso"
},
"about": {
"AboutOpendtu": "About OpenDTU",
"Documentation": "Documentazione",
"DocumentationBody": "La documentazione firmware e hardware sono disponibili qui: <a href=\"https://www.opendtu.solar\" target=\"_blank\">https://www.opendtu.solar</a>",
"ProjectOrigin": "Origine Progetto",
"ProjectOriginBody1": "Questo progetto è partito da <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">questa discussione. (Mikrocontroller.net)</a>",
"ProjectOriginBody2": "Il protocollo Hoymiles è stato decriptato grazie al contributo volontario di molti programmatori. OpenDTU, fra gli altri, è stato sviluppato grazie a questo lavoro. Il progetto è distribuito con Licenza Open Source (<a href=\"https://www.gnu.de/documents/gpl-2.0.de.html\" target=\"_blank\">GNU General Public License version 2</a>).",
"ProjectOriginBody3": "Il software è stato sviluppato con le nostre migliori conoscenze e convinzioni. Tuttavia, non si assume alcuna responsabilità per malfunzionamenti o perdita di garanzia dell'inverter.",
"ProjectOriginBody4": "OpenDTU è disponibile gratuitamente. Se hai pagato per questo software, probabilmente sei stato truffato.",
"NewsUpdates": "Novità e Aggiornamenti",
"NewsUpdatesBody": "Nuovi aggiornamenti sono disponibili su Github: <a href=\"https://github.com/tbnobody/OpenDTU\" target=\"_blank\">https://github.com/tbnobody/OpenDTU</a>",
"ErrorReporting": "Segnalazione Errori",
"ErrorReportingBody": "Per favore segnala eventuali problemi utilizzando le funzionalità della piattaforma <a href=\"https://github.com/tbnobody/OpenDTU/issues\" target=\"_blank\">Github</a>",
"Discussion": "Discussioni",
"DiscussionBody": "Puoi avviare una discussione con noi su <a href=\"https://discord.gg/WzhxEY62mB\" target=\"_blank\">Discord</a> o <a href=\"https://github.com/tbnobody/OpenDTU/discussions\" target=\"_blank\">Github</a>"
},
"hints": {
"RadioProblem": "Non è possibile dialogare con il modulo radio selezionato. Controlla i collegamenti alla radio.",
"TimeSync": "La Data/Ora non sono state sincronizzate, ed in tal caso non è possibile eseguire richieste all'inverter. Questa condizione è normale appena avviato, tuttavia dopo un po' (>1 minuto), questa situazione potrebbe indicare un problema di accesso al server NTP.",
"TimeSyncLink": "Controlla le impostazioni Data/Ora.",
"DefaultPassword": "Stai usando la password di default per accedere all'interfaccia web e per la modalità Access Point di emergenza. Questo può portare ad un rischio di sicurezza.",
"DefaultPasswordLink": "Per favore cambia la password.",
"PinMappingIssue": "You are using a generic firmware image, but have not yet uploaded a file with device profiles (<code>pin_mapping.json</code>) or have not selected a profile defined there. Please refer to the <a href=\"https://opendtu.solar/firmware/device_profiles/\" target=\"_blank\" class=\"alert-link\">documentation</a> for details."
},
"deviceadmin": {
"DeviceManager": "Device-Manager",
"ParseError": "Parse error in 'pin_mapping.json': {error}",
"PinAssignment": "Impostazioni Connessione",
"SelectedProfile": "Profilo selezionato",
"DefaultProfile": "(Impostazioni di Default)",
"ProfileHint": "Il tuo dispositivo potrebbe smettere di rispondere selezionando un profilo incompatibile. In questo caso, dovrai eseguire una cancellazione collegandoti all'interfaccia seriale.",
"Display": "Display",
"PowerSafe": "Abilita Risparmio Energetico",
"PowerSafeHint": "Spegni il display se l'inverter non produce.",
"Screensaver": "Abilita Screensaver",
"ScreensaverHint": "Muove il testo nel display per prevenire danneggiamento pixel. (Utile in caso di display OLED)",
"DiagramMode": "Modalità grafica",
"off": "Off",
"small": "Small",
"fullscreen": "Fullscreen",
"DiagramDuration": "Durata grafico",
"DiagramDurationHint": "Periodo che viene mostrato nel grafico.",
"Seconds": "Secondi",
"Contrast": "Contrasto ({contrast})",
"Rotation": "Rotazione",
"rot0": "Nessuna rotazione",
"rot90": "Rotazione 90 gradi",
"rot180": "Rotazione 180 gradi",
"rot270": "Rotazione 270 gradi",
"DisplayLanguage": "Linuga Display",
"en": "English",
"de": "German",
"fr": "French",
"Leds": "LEDs",
"EqualBrightness": "Equalizza luminosità",
"LedBrightness": "LED {led}, Luminosità ({brightness})"
},
"pininfo": {
"Category": "Categoria",
"Name": "Nome",
"Number": "Numero",
"ValueSelected": "Selezionato",
"ValueActive": "Attivo"
},
"inputserial": {
"format_hoymiles": "Hoymiles serial number format",
"format_converted": "Already converted serial number",
"format_herf_valid": "E-Star HERF format (will be saved converted): {serial}",
"format_herf_invalid": "E-Star HERF format: Invalid checksum",
"format_unknown": "Unknown format"
}
}
}

View File

@ -1,778 +0,0 @@
/*
* 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.c
* @brief CMT2300A transceiver RF chip driver
*
* @version 1.3
* @date Jul 17 2017
* @author CMOSTEK R@D
*/
#include "cmt2300a.h"
/*! ********************************************************
* @name CMT2300A_SoftReset
* @desc Soft reset.
* *********************************************************/
void CMT2300A_SoftReset(void)
{
CMT2300A_WriteReg(0x7F, 0xFF);
}
/*! ********************************************************
* @name CMT2300A_GetChipStatus
* @desc Get the chip status.
* @return
* CMT2300A_STA_PUP
* CMT2300A_STA_SLEEP
* CMT2300A_STA_STBY
* CMT2300A_STA_RFS
* CMT2300A_STA_TFS
* CMT2300A_STA_RX
* CMT2300A_STA_TX
* CMT2300A_STA_EEPROM
* CMT2300A_STA_ERROR
* CMT2300A_STA_CAL
* *********************************************************/
uint8_t CMT2300A_GetChipStatus(void)
{
return CMT2300A_ReadReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA;
}
/*! ********************************************************
* @name CMT2300A_AutoSwitchStatus
* @desc Auto switch the chip status, and 10 ms as timeout.
* @param nGoCmd: the chip next status
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_AutoSwitchStatus(uint8_t nGoCmd)
{
#ifdef ENABLE_AUTO_SWITCH_CHIP_STATUS
uint32_t nBegTick = CMT2300A_GetTickCount();
uint8_t nWaitStatus = 0;
switch (nGoCmd) {
case CMT2300A_GO_SLEEP:
nWaitStatus = CMT2300A_STA_SLEEP;
break;
case CMT2300A_GO_STBY:
nWaitStatus = CMT2300A_STA_STBY;
break;
case CMT2300A_GO_TFS:
nWaitStatus = CMT2300A_STA_TFS;
break;
case CMT2300A_GO_TX:
nWaitStatus = CMT2300A_STA_TX;
break;
case CMT2300A_GO_RFS:
nWaitStatus = CMT2300A_STA_RFS;
break;
case CMT2300A_GO_RX:
nWaitStatus = CMT2300A_STA_RX;
break;
}
CMT2300A_WriteReg(CMT2300A_CUS_MODE_CTL, nGoCmd);
while (CMT2300A_GetTickCount() - nBegTick < 10) {
CMT2300A_DelayUs(100);
if (nWaitStatus == CMT2300A_GetChipStatus())
return true;
if (CMT2300A_GO_TX == nGoCmd) {
CMT2300A_DelayUs(100);
if (CMT2300A_MASK_TX_DONE_FLG & CMT2300A_ReadReg(CMT2300A_CUS_INT_CLR1))
return true;
}
if (CMT2300A_GO_RX == nGoCmd) {
CMT2300A_DelayUs(100);
if (CMT2300A_MASK_PKT_OK_FLG & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG))
return true;
}
}
return false;
#else
CMT2300A_WriteReg(CMT2300A_CUS_MODE_CTL, nGoCmd);
return true;
#endif
}
/*! ********************************************************
* @name CMT2300A_GoSleep
* @desc Entry SLEEP mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoSleep(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_SLEEP);
}
/*! ********************************************************
* @name CMT2300A_GoStby
* @desc Entry Sleep mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoStby(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_STBY);
}
/*! ********************************************************
* @name CMT2300A_GoTFS
* @desc Entry TFS mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoTFS(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_TFS);
}
/*! ********************************************************
* @name CMT2300A_GoRFS
* @desc Entry RFS mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoRFS(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_RFS);
}
/*! ********************************************************
* @name CMT2300A_GoTx
* @desc Entry Tx mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoTx(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_TX);
}
/*! ********************************************************
* @name CMT2300A_GoRx
* @desc Entry Rx mode.
* @return TRUE or FALSE
* *********************************************************/
bool CMT2300A_GoRx(void)
{
return CMT2300A_AutoSwitchStatus(CMT2300A_GO_RX);
}
/*! ********************************************************
* @name CMT2300A_ConfigGpio
* @desc Config GPIO pins mode.
* @param nGpioSel: GPIO1_SEL | GPIO2_SEL | GPIO3_SEL | GPIO4_SEL
* GPIO1_SEL:
* CMT2300A_GPIO1_SEL_DOUT/DIN
* CMT2300A_GPIO1_SEL_INT1
* CMT2300A_GPIO1_SEL_INT2
* CMT2300A_GPIO1_SEL_DCLK
*
* GPIO2_SEL:
* CMT2300A_GPIO2_SEL_INT1
* CMT2300A_GPIO2_SEL_INT2
* CMT2300A_GPIO2_SEL_DOUT/DIN
* CMT2300A_GPIO2_SEL_DCLK
*
* GPIO3_SEL:
* CMT2300A_GPIO3_SEL_CLKO
* CMT2300A_GPIO3_SEL_DOUT/DIN
* CMT2300A_GPIO3_SEL_INT2
* CMT2300A_GPIO3_SEL_DCLK
*
* GPIO4_SEL:
* CMT2300A_GPIO4_SEL_RSTIN
* CMT2300A_GPIO4_SEL_INT1
* CMT2300A_GPIO4_SEL_DOUT
* CMT2300A_GPIO4_SEL_DCLK
* *********************************************************/
void CMT2300A_ConfigGpio(uint8_t nGpioSel)
{
CMT2300A_WriteReg(CMT2300A_CUS_IO_SEL, nGpioSel);
}
/*! ********************************************************
* @name CMT2300A_ConfigInterrupt
* @desc Config interrupt on INT1 and INT2.
* @param nInt1Sel, nInt2Sel
* CMT2300A_INT_SEL_RX_ACTIVE
* CMT2300A_INT_SEL_TX_ACTIVE
* CMT2300A_INT_SEL_RSSI_VLD
* CMT2300A_INT_SEL_PREAM_OK
* CMT2300A_INT_SEL_SYNC_OK
* CMT2300A_INT_SEL_NODE_OK
* CMT2300A_INT_SEL_CRC_OK
* CMT2300A_INT_SEL_PKT_OK
* CMT2300A_INT_SEL_SL_TMO
* CMT2300A_INT_SEL_RX_TMO
* CMT2300A_INT_SEL_TX_DONE
* CMT2300A_INT_SEL_RX_FIFO_NMTY
* CMT2300A_INT_SEL_RX_FIFO_TH
* CMT2300A_INT_SEL_RX_FIFO_FULL
* CMT2300A_INT_SEL_RX_FIFO_WBYTE
* CMT2300A_INT_SEL_RX_FIFO_OVF
* CMT2300A_INT_SEL_TX_FIFO_NMTY
* CMT2300A_INT_SEL_TX_FIFO_TH
* CMT2300A_INT_SEL_TX_FIFO_FULL
* CMT2300A_INT_SEL_STATE_IS_STBY
* CMT2300A_INT_SEL_STATE_IS_FS
* CMT2300A_INT_SEL_STATE_IS_RX
* CMT2300A_INT_SEL_STATE_IS_TX
* CMT2300A_INT_SEL_LED
* CMT2300A_INT_SEL_TRX_ACTIVE
* CMT2300A_INT_SEL_PKT_DONE
* *********************************************************/
void CMT2300A_ConfigInterrupt(uint8_t nInt1Sel, uint8_t nInt2Sel)
{
nInt1Sel &= CMT2300A_MASK_INT1_SEL;
nInt1Sel |= (~CMT2300A_MASK_INT1_SEL) & CMT2300A_ReadReg(CMT2300A_CUS_INT1_CTL);
CMT2300A_WriteReg(CMT2300A_CUS_INT1_CTL, nInt1Sel);
nInt2Sel &= CMT2300A_MASK_INT2_SEL;
nInt2Sel |= (~CMT2300A_MASK_INT2_SEL) & CMT2300A_ReadReg(CMT2300A_CUS_INT2_CTL);
CMT2300A_WriteReg(CMT2300A_CUS_INT2_CTL, nInt2Sel);
}
/*! ********************************************************
* @name CMT2300A_SetInterruptPolar
* @desc Set the polarity of the interrupt.
* @param bEnable(TRUE): active-high (default)
* bEnable(FALSE): active-low
* *********************************************************/
void CMT2300A_SetInterruptPolar(bool bActiveHigh)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_INT1_CTL);
if (bActiveHigh)
tmp &= ~CMT2300A_MASK_INT_POLAR;
else
tmp |= CMT2300A_MASK_INT_POLAR;
CMT2300A_WriteReg(CMT2300A_CUS_INT1_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_SetFifoThreshold
* @desc Set FIFO threshold.
* @param nFifoThreshold
* *********************************************************/
void CMT2300A_SetFifoThreshold(uint8_t nFifoThreshold)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_PKT29);
tmp &= ~CMT2300A_MASK_FIFO_TH;
tmp |= nFifoThreshold & CMT2300A_MASK_FIFO_TH;
CMT2300A_WriteReg(CMT2300A_CUS_PKT29, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableAntennaSwitch
* @desc Enable antenna switch, output TX_ACTIVE/RX_ACTIVE
* via GPIO1/GPIO2.
* @param nMode
* 0: RF_SWT1_EN=1, RF_SWT2_EN=0
* GPIO1: RX_ACTIVE, GPIO2: TX_ACTIVE
* 1: RF_SWT1_EN=0, RF_SWT2_EN=1
* GPIO1: RX_ACTIVE, GPIO2: ~RX_ACTIVE
* *********************************************************/
void CMT2300A_EnableAntennaSwitch(uint8_t nMode)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_INT1_CTL);
if (0 == nMode) {
tmp |= CMT2300A_MASK_RF_SWT1_EN;
tmp &= ~CMT2300A_MASK_RF_SWT2_EN;
} else if (1 == nMode) {
tmp &= ~CMT2300A_MASK_RF_SWT1_EN;
tmp |= CMT2300A_MASK_RF_SWT2_EN;
}
CMT2300A_WriteReg(CMT2300A_CUS_INT1_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableInterrupt
* @desc Enable interrupt.
* @param nEnable
* CMT2300A_MASK_SL_TMO_EN |
* CMT2300A_MASK_RX_TMO_EN |
* CMT2300A_MASK_TX_DONE_EN |
* CMT2300A_MASK_PREAM_OK_EN |
* CMT2300A_MASK_SYNC_OK_EN |
* CMT2300A_MASK_NODE_OK_EN |
* CMT2300A_MASK_CRC_OK_EN |
* CMT2300A_MASK_PKT_DONE_EN
* *********************************************************/
void CMT2300A_EnableInterrupt(uint8_t nEnable)
{
CMT2300A_WriteReg(CMT2300A_CUS_INT_EN, nEnable);
}
/*! ********************************************************
* @name CMT2300A_EnableRxFifoAutoClear
* @desc Auto clear Rx FIFO before entry Rx mode.
* @param bEnable(TRUE): Enable it(default)
* bEnable(FALSE): Disable it
* *********************************************************/
void CMT2300A_EnableRxFifoAutoClear(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
if (bEnable)
tmp &= ~CMT2300A_MASK_FIFO_AUTO_CLR_DIS;
else
tmp |= CMT2300A_MASK_FIFO_AUTO_CLR_DIS;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableFifoMerge
* @desc Enable FIFO merge.
* @param bEnable(TRUE): use a single 64-byte FIFO for either Tx or Rx
* bEnable(FALSE): use a 32-byte FIFO for Tx and another 32-byte FIFO for Rx(default)
* *********************************************************/
void CMT2300A_EnableFifoMerge(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
if (bEnable)
tmp |= CMT2300A_MASK_FIFO_MERGE_EN;
else
tmp &= ~CMT2300A_MASK_FIFO_MERGE_EN;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableReadFifo
* @desc Enable SPI to read the FIFO.
* *********************************************************/
void CMT2300A_EnableReadFifo(void)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
tmp &= ~CMT2300A_MASK_SPI_FIFO_RD_WR_SEL;
tmp &= ~CMT2300A_MASK_FIFO_RX_TX_SEL;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableWriteFifo
* @desc Enable SPI to write the FIFO.
* *********************************************************/
void CMT2300A_EnableWriteFifo(void)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
tmp |= CMT2300A_MASK_SPI_FIFO_RD_WR_SEL;
tmp |= CMT2300A_MASK_FIFO_RX_TX_SEL;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_RestoreFifo
* @desc Restore the FIFO.
* *********************************************************/
void CMT2300A_RestoreFifo(void)
{
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CLR, CMT2300A_MASK_FIFO_RESTORE);
}
/*! ********************************************************
* @name CMT2300A_ClearFifo
* @desc Clear the Tx FIFO.
* @return FIFO flags
* CMT2300A_MASK_RX_FIFO_FULL_FLG |
* CMT2300A_MASK_RX_FIFO_NMTY_FLG |
* CMT2300A_MASK_RX_FIFO_TH_FLG |
* CMT2300A_MASK_RX_FIFO_OVF_FLG |
* CMT2300A_MASK_TX_FIFO_FULL_FLG |
* CMT2300A_MASK_TX_FIFO_NMTY_FLG |
* CMT2300A_MASK_TX_FIFO_TH_FLG
* *********************************************************/
uint8_t CMT2300A_ClearTxFifo(void)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_FLAG);
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CLR, CMT2300A_MASK_FIFO_CLR_TX);
return tmp;
}
/*! ********************************************************
* @name CMT2300A_ClearFifo
* @desc Clear the Rx FIFO.
* @return FIFO flags
* CMT2300A_MASK_RX_FIFO_FULL_FLG |
* CMT2300A_MASK_RX_FIFO_NMTY_FLG |
* CMT2300A_MASK_RX_FIFO_TH_FLG |
* CMT2300A_MASK_RX_FIFO_OVF_FLG |
* CMT2300A_MASK_TX_FIFO_FULL_FLG |
* CMT2300A_MASK_TX_FIFO_NMTY_FLG |
* CMT2300A_MASK_TX_FIFO_TH_FLG
* *********************************************************/
uint8_t CMT2300A_ClearRxFifo(void)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_FLAG);
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CLR, CMT2300A_MASK_FIFO_CLR_RX);
return tmp;
}
/*! ********************************************************
* @name CMT2300A_ClearInterruptFlags
* @desc Clear all interrupt flags.
* @return Some interrupt flags
* CMT2300A_MASK_SL_TMO_EN |
* CMT2300A_MASK_RX_TMO_EN |
* CMT2300A_MASK_TX_DONE_EN |
* CMT2300A_MASK_PREAM_OK_FLG |
* CMT2300A_MASK_SYNC_OK_FLG |
* CMT2300A_MASK_NODE_OK_FLG |
* CMT2300A_MASK_CRC_OK_FLG |
* CMT2300A_MASK_PKT_OK_FLG
* *********************************************************/
uint8_t CMT2300A_ClearInterruptFlags(void)
{
uint8_t nFlag1, nFlag2;
uint8_t nClr1 = 0;
uint8_t nClr2 = 0;
uint8_t nRet = 0;
uint8_t nIntPolar;
nIntPolar = CMT2300A_ReadReg(CMT2300A_CUS_INT1_CTL);
nIntPolar = (nIntPolar & CMT2300A_MASK_INT_POLAR) ? 1 : 0;
nFlag1 = CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG);
nFlag2 = CMT2300A_ReadReg(CMT2300A_CUS_INT_CLR1);
if (nIntPolar) {
/* Interrupt flag active-low */
nFlag1 = ~nFlag1;
nFlag2 = ~nFlag2;
}
if (CMT2300A_MASK_LBD_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_LBD_CLR; /* Clear LBD_FLG */
}
if (CMT2300A_MASK_COL_ERR_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_PKT_DONE_CLR; /* Clear COL_ERR_FLG by PKT_DONE_CLR */
}
if (CMT2300A_MASK_PKT_ERR_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_PKT_DONE_CLR; /* Clear PKT_ERR_FLG by PKT_DONE_CLR */
}
if (CMT2300A_MASK_PREAM_OK_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_PREAM_OK_CLR; /* Clear PREAM_OK_FLG */
nRet |= CMT2300A_MASK_PREAM_OK_FLG; /* Return PREAM_OK_FLG */
}
if (CMT2300A_MASK_SYNC_OK_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_SYNC_OK_CLR; /* Clear SYNC_OK_FLG */
nRet |= CMT2300A_MASK_SYNC_OK_FLG; /* Return SYNC_OK_FLG */
}
if (CMT2300A_MASK_NODE_OK_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_NODE_OK_CLR; /* Clear NODE_OK_FLG */
nRet |= CMT2300A_MASK_NODE_OK_FLG; /* Return NODE_OK_FLG */
}
if (CMT2300A_MASK_CRC_OK_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_CRC_OK_CLR; /* Clear CRC_OK_FLG */
nRet |= CMT2300A_MASK_CRC_OK_FLG; /* Return CRC_OK_FLG */
}
if (CMT2300A_MASK_PKT_OK_FLG & nFlag1) {
nClr2 |= CMT2300A_MASK_PKT_DONE_CLR; /* Clear PKT_OK_FLG */
nRet |= CMT2300A_MASK_PKT_OK_FLG; /* Return PKT_OK_FLG */
}
if (CMT2300A_MASK_SL_TMO_FLG & nFlag2) {
nClr1 |= CMT2300A_MASK_SL_TMO_CLR; /* Clear SL_TMO_FLG */
nRet |= CMT2300A_MASK_SL_TMO_EN; /* Return SL_TMO_FLG by SL_TMO_EN */
}
if (CMT2300A_MASK_RX_TMO_FLG & nFlag2) {
nClr1 |= CMT2300A_MASK_RX_TMO_CLR; /* Clear RX_TMO_FLG */
nRet |= CMT2300A_MASK_RX_TMO_EN; /* Return RX_TMO_FLG by RX_TMO_EN */
}
if (CMT2300A_MASK_TX_DONE_FLG & nFlag2) {
nClr1 |= CMT2300A_MASK_TX_DONE_CLR; /* Clear TX_DONE_FLG */
nRet |= CMT2300A_MASK_TX_DONE_EN; /* Return TX_DONE_FLG by TX_DONE_EN */
}
CMT2300A_WriteReg(CMT2300A_CUS_INT_CLR1, nClr1);
CMT2300A_WriteReg(CMT2300A_CUS_INT_CLR2, nClr2);
if (nIntPolar) {
/* Interrupt flag active-low */
nRet = ~nRet;
}
return nRet;
}
/*! ********************************************************
* @name CMT2300A_ConfigTxDin
* @desc Used to select whether to use GPIO1 or GPIO2 or GPIO3
* as DIN in the direct mode. It only takes effect when
* call CMT2300A_EnableTxDin(TRUE) in the direct mode.
* @param nDinSel
* CMT2300A_TX_DIN_SEL_GPIO1
* CMT2300A_TX_DIN_SEL_GPIO2
* CMT2300A_TX_DIN_SEL_GPIO3
* *********************************************************/
void CMT2300A_ConfigTxDin(uint8_t nDinSel)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
tmp &= ~CMT2300A_MASK_TX_DIN_SEL;
tmp |= nDinSel;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableTxDin
* @desc Used to change GPIO1/GPIO2/GPIO3 between DOUT and DIN.
* @param bEnable(TRUE): used as DIN
* bEnable(FALSE): used as DOUT(default)
* *********************************************************/
void CMT2300A_EnableTxDin(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FIFO_CTL);
if (bEnable)
tmp |= CMT2300A_MASK_TX_DIN_EN;
else
tmp &= ~CMT2300A_MASK_TX_DIN_EN;
CMT2300A_WriteReg(CMT2300A_CUS_FIFO_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableTxDinInvert
* @desc Used to invert DIN data in direct mode.
* @param bEnable(TRUE): invert DIN
* bEnable(FALSE): not invert DIN(default)
* *********************************************************/
void CMT2300A_EnableTxDinInvert(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_INT2_CTL);
if (bEnable)
tmp |= CMT2300A_MASK_TX_DIN_INV;
else
tmp &= ~CMT2300A_MASK_TX_DIN_INV;
CMT2300A_WriteReg(CMT2300A_CUS_INT2_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_IsExist
* @desc Chip indentify.
* @return TRUE: chip is exist, FALSE: chip not found
* *********************************************************/
bool CMT2300A_IsExist(void)
{
uint8_t back, dat;
back = CMT2300A_ReadReg(CMT2300A_CUS_PKT17);
CMT2300A_WriteReg(CMT2300A_CUS_PKT17, 0xAA);
dat = CMT2300A_ReadReg(CMT2300A_CUS_PKT17);
CMT2300A_WriteReg(CMT2300A_CUS_PKT17, back);
if (0xAA == dat)
return true;
else
return false;
}
/*! ********************************************************
* @name CMT2300A_GetRssiCode
* @desc Get RSSI code.
* @return RSSI code
* *********************************************************/
uint8_t CMT2300A_GetRssiCode(void)
{
return CMT2300A_ReadReg(CMT2300A_CUS_RSSI_CODE);
}
/*! ********************************************************
* @name CMT2300A_GetRssiDBm
* @desc Get RSSI dBm.
* @return dBm
* *********************************************************/
int CMT2300A_GetRssiDBm(void)
{
return (int)CMT2300A_ReadReg(CMT2300A_CUS_RSSI_DBM) - 128;
}
/*! ********************************************************
* @name CMT2300A_SetFrequencyChannel
* @desc This defines up to 255 frequency channel
* for fast frequency hopping operation.
* @param nChann: the frequency channel
* *********************************************************/
void CMT2300A_SetFrequencyChannel(const uint8_t nChann)
{
CMT2300A_WriteReg(CMT2300A_CUS_FREQ_CHNL, nChann);
}
/*! ********************************************************
* @name CMT2300A_SetFrequencyStep
* @desc This defines the frequency channel step size
* for fast frequency hopping operation.
* One step size is 2.5 kHz.
* @param nOffset: the frequency step
* *********************************************************/
void CMT2300A_SetFrequencyStep(uint8_t nOffset)
{
CMT2300A_WriteReg(CMT2300A_CUS_FREQ_OFS, nOffset);
}
/*! ********************************************************
* @name CMT2300A_SetPayloadLength
* @desc Set payload length.
* @param nLength
* *********************************************************/
void CMT2300A_SetPayloadLength(uint16_t nLength)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_PKT14);
tmp &= ~CMT2300A_MASK_PAYLOAD_LENG_10_8;
tmp |= (nLength >> 4) & CMT2300A_MASK_PAYLOAD_LENG_10_8;
CMT2300A_WriteReg(CMT2300A_CUS_PKT14, tmp);
tmp = nLength & CMT2300A_MASK_PAYLOAD_LENG_7_0;
CMT2300A_WriteReg(CMT2300A_CUS_PKT15, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableLfosc
* @desc If you need use sleep timer, you should enable LFOSC.
* @param bEnable(TRUE): Enable it(default)
* bEnable(FALSE): Disable it
* *********************************************************/
void CMT2300A_EnableLfosc(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_SYS2);
if (bEnable) {
tmp |= CMT2300A_MASK_LFOSC_RECAL_EN;
tmp |= CMT2300A_MASK_LFOSC_CAL1_EN;
tmp |= CMT2300A_MASK_LFOSC_CAL2_EN;
} else {
tmp &= ~CMT2300A_MASK_LFOSC_RECAL_EN;
tmp &= ~CMT2300A_MASK_LFOSC_CAL1_EN;
tmp &= ~CMT2300A_MASK_LFOSC_CAL2_EN;
}
CMT2300A_WriteReg(CMT2300A_CUS_SYS2, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableLfoscOutput
* @desc LFOSC clock is output via GPIO3.
* @param bEnable(TRUE): Enable it
* bEnable(FALSE): Disable it(default)
* *********************************************************/
void CMT2300A_EnableLfoscOutput(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_INT2_CTL);
if (bEnable)
tmp |= CMT2300A_MASK_LFOSC_OUT_EN;
else
tmp &= ~CMT2300A_MASK_LFOSC_OUT_EN;
CMT2300A_WriteReg(CMT2300A_CUS_INT2_CTL, tmp);
}
/*! ********************************************************
* @name CMT2300A_EnableAfc
* @desc AFC enable or disanble.
* @param bEnable(TRUE): Enable it
* bEnable(FALSE): Disable it(default)
* *********************************************************/
void CMT2300A_EnableAfc(bool bEnable)
{
uint8_t tmp = CMT2300A_ReadReg(CMT2300A_CUS_FSK5);
if (bEnable)
tmp |= 0x10;
else
tmp &= ~0x10;
CMT2300A_WriteReg(CMT2300A_CUS_FSK5, tmp);
}
/*! ********************************************************
* @name CMT2300A_SetAfcOvfTh
* @desc This is optional, only needed when using Rx fast frequency hopping.
* @param afcOvfTh: AFC_OVF_TH see AN142 and AN197 for details.
* *********************************************************/
void CMT2300A_SetAfcOvfTh(uint8_t afcOvfTh)
{
CMT2300A_WriteReg(CMT2300A_CUS_FSK4, afcOvfTh);
}
/*! ********************************************************
* @name CMT2300A_Init
* @desc Initialize chip status.
* *********************************************************/
bool CMT2300A_Init(void)
{
uint8_t tmp;
CMT2300A_SoftReset();
CMT2300A_DelayMs(20);
if (!CMT2300A_GoStby())
return false; // CMT2300A not switched to standby mode!
if (!CMT2300A_IsExist())
return false; // CMT2300A not found!
tmp = CMT2300A_ReadReg(CMT2300A_CUS_MODE_STA);
tmp |= CMT2300A_MASK_CFG_RETAIN; /* Enable CFG_RETAIN */
tmp &= ~CMT2300A_MASK_RSTN_IN_EN; /* Disable RSTN_IN */
CMT2300A_WriteReg(CMT2300A_CUS_MODE_STA, tmp);
tmp = CMT2300A_ReadReg(CMT2300A_CUS_EN_CTL);
tmp |= CMT2300A_MASK_LOCKING_EN; /* Enable LOCKING_EN */
CMT2300A_WriteReg(CMT2300A_CUS_EN_CTL, tmp);
CMT2300A_EnableLfosc(false); /* Disable LFOSC */
CMT2300A_ClearInterruptFlags();
return true;
}
/*! ********************************************************
* @name CMT2300A_ConfigRegBank
* @desc Config one register bank.
* *********************************************************/
bool CMT2300A_ConfigRegBank(uint8_t base_addr, const uint8_t bank[], uint8_t len)
{
uint8_t i;
for (i = 0; i < len; i++)
CMT2300A_WriteReg(i + base_addr, bank[i]);
return true;
}

View File

@ -1,96 +0,0 @@
/*
* 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

View File

@ -1,606 +0,0 @@
/*
* 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_defs.h
* @brief CMT2300A registers defines
*
* @version 1.2
* @date Jul 17 2017
* @author CMOSTEK R@D
*/
#ifndef __CMT2300A_DEFS_H
#define __CMT2300A_DEFS_H
/* ---------- CMT bank defines ---------- */
#define CMT2300A_CMT_BANK_ADDR 0x00
#define CMT2300A_CMT_BANK_SIZE 12
#define CMT2300A_CUS_CMT1 0x00
#define CMT2300A_CUS_CMT2 0x01
#define CMT2300A_CUS_CMT3 0x02
#define CMT2300A_CUS_CMT4 0x03
#define CMT2300A_CUS_CMT5 0x04
#define CMT2300A_CUS_CMT6 0x05
#define CMT2300A_CUS_CMT7 0x06
#define CMT2300A_CUS_CMT8 0x07
#define CMT2300A_CUS_CMT9 0x08
#define CMT2300A_CUS_CMT10 0x09
#define CMT2300A_CUS_CMT11 0x0A
#define CMT2300A_CUS_RSSI 0x0B
/* ---------- System bank defines ---------- */
#define CMT2300A_SYSTEM_BANK_ADDR 0x0C
#define CMT2300A_SYSTEM_BANK_SIZE 12
#define CMT2300A_CUS_SYS1 0x0C
#define CMT2300A_CUS_SYS2 0x0D
#define CMT2300A_CUS_SYS3 0x0E
#define CMT2300A_CUS_SYS4 0x0F
#define CMT2300A_CUS_SYS5 0x10
#define CMT2300A_CUS_SYS6 0x11
#define CMT2300A_CUS_SYS7 0x12
#define CMT2300A_CUS_SYS8 0x13
#define CMT2300A_CUS_SYS9 0x14
#define CMT2300A_CUS_SYS10 0x15
#define CMT2300A_CUS_SYS11 0x16
#define CMT2300A_CUS_SYS12 0x17
/* ---------- Frequency bank defines ---------- */
#define CMT2300A_FREQUENCY_BANK_ADDR 0x18
#define CMT2300A_FREQUENCY_BANK_SIZE 8
#define CMT2300A_CUS_RF1 0x18
#define CMT2300A_CUS_RF2 0x19
#define CMT2300A_CUS_RF3 0x1A
#define CMT2300A_CUS_RF4 0x1B
#define CMT2300A_CUS_RF5 0x1C
#define CMT2300A_CUS_RF6 0x1D
#define CMT2300A_CUS_RF7 0x1E
#define CMT2300A_CUS_RF8 0x1F
/* ---------- Data rate bank defines ---------- */
#define CMT2300A_DATA_RATE_BANK_ADDR 0x20
#define CMT2300A_DATA_RATE_BANK_SIZE 24
#define CMT2300A_CUS_RF9 0x20
#define CMT2300A_CUS_RF10 0x21
#define CMT2300A_CUS_RF11 0x22
#define CMT2300A_CUS_RF12 0x23
#define CMT2300A_CUS_FSK1 0x24
#define CMT2300A_CUS_FSK2 0x25
#define CMT2300A_CUS_FSK3 0x26
#define CMT2300A_CUS_FSK4 0x27
#define CMT2300A_CUS_FSK5 0x28
#define CMT2300A_CUS_FSK6 0x29
#define CMT2300A_CUS_FSK7 0x2A
#define CMT2300A_CUS_CDR1 0x2B
#define CMT2300A_CUS_CDR2 0x2C
#define CMT2300A_CUS_CDR3 0x2D
#define CMT2300A_CUS_CDR4 0x2E
#define CMT2300A_CUS_AGC1 0x2F
#define CMT2300A_CUS_AGC2 0x30
#define CMT2300A_CUS_AGC3 0x31
#define CMT2300A_CUS_AGC4 0x32
#define CMT2300A_CUS_OOK1 0x33
#define CMT2300A_CUS_OOK2 0x34
#define CMT2300A_CUS_OOK3 0x35
#define CMT2300A_CUS_OOK4 0x36
#define CMT2300A_CUS_OOK5 0x37
/* ---------- Baseband bank defines ---------- */
#define CMT2300A_BASEBAND_BANK_ADDR 0x38
#define CMT2300A_BASEBAND_BANK_SIZE 29
#define CMT2300A_CUS_PKT1 0x38
#define CMT2300A_CUS_PKT2 0x39
#define CMT2300A_CUS_PKT3 0x3A
#define CMT2300A_CUS_PKT4 0x3B
#define CMT2300A_CUS_PKT5 0x3C
#define CMT2300A_CUS_PKT6 0x3D
#define CMT2300A_CUS_PKT7 0x3E
#define CMT2300A_CUS_PKT8 0x3F
#define CMT2300A_CUS_PKT9 0x40
#define CMT2300A_CUS_PKT10 0x41
#define CMT2300A_CUS_PKT11 0x42
#define CMT2300A_CUS_PKT12 0x43
#define CMT2300A_CUS_PKT13 0x44
#define CMT2300A_CUS_PKT14 0x45
#define CMT2300A_CUS_PKT15 0x46
#define CMT2300A_CUS_PKT16 0x47
#define CMT2300A_CUS_PKT17 0x48
#define CMT2300A_CUS_PKT18 0x49
#define CMT2300A_CUS_PKT19 0x4A
#define CMT2300A_CUS_PKT20 0x4B
#define CMT2300A_CUS_PKT21 0x4C
#define CMT2300A_CUS_PKT22 0x4D
#define CMT2300A_CUS_PKT23 0x4E
#define CMT2300A_CUS_PKT24 0x4F
#define CMT2300A_CUS_PKT25 0x50
#define CMT2300A_CUS_PKT26 0x51
#define CMT2300A_CUS_PKT27 0x52
#define CMT2300A_CUS_PKT28 0x53
#define CMT2300A_CUS_PKT29 0x54
/* ---------- Tx bank defines ---------- */
#define CMT2300A_TX_BANK_ADDR 0x55
#define CMT2300A_TX_BANK_SIZE 11
#define CMT2300A_CUS_TX1 0x55
#define CMT2300A_CUS_TX2 0x56
#define CMT2300A_CUS_TX3 0x57
#define CMT2300A_CUS_TX4 0x58
#define CMT2300A_CUS_TX5 0x59
#define CMT2300A_CUS_TX6 0x5A
#define CMT2300A_CUS_TX7 0x5B
#define CMT2300A_CUS_TX8 0x5C
#define CMT2300A_CUS_TX9 0x5D
#define CMT2300A_CUS_TX10 0x5E
#define CMT2300A_CUS_LBD 0x5F
/* ---------- Control1 bank defines ---------- */
#define CMT2300A_CONTROL1_BANK_ADDR 0x60
#define CMT2300A_CONTROL1_BANK_SIZE 11
#define CMT2300A_CUS_MODE_CTL 0x60
#define CMT2300A_CUS_MODE_STA 0x61
#define CMT2300A_CUS_EN_CTL 0x62
#define CMT2300A_CUS_FREQ_CHNL 0x63
#define CMT2300A_CUS_FREQ_OFS 0x64
#define CMT2300A_CUS_IO_SEL 0x65
#define CMT2300A_CUS_INT1_CTL 0x66
#define CMT2300A_CUS_INT2_CTL 0x67
#define CMT2300A_CUS_INT_EN 0x68
#define CMT2300A_CUS_FIFO_CTL 0x69
#define CMT2300A_CUS_INT_CLR1 0x6A
/* ---------- Control2 bank defines ---------- */
#define CMT2300A_CONTROL2_BANK_ADDR 0x6B
#define CMT2300A_CONTROL2_BANK_SIZE 7
#define CMT2300A_CUS_INT_CLR2 0x6B
#define CMT2300A_CUS_FIFO_CLR 0x6C
#define CMT2300A_CUS_INT_FLAG 0x6D
#define CMT2300A_CUS_FIFO_FLAG 0x6E
#define CMT2300A_CUS_RSSI_CODE 0x6F
#define CMT2300A_CUS_RSSI_DBM 0x70
#define CMT2300A_CUS_LBD_RESULT 0x71
/* ********** CMT2300A_CUS_CMT2 registers ********** */
#define CMT2300A_MASK_PRODUCT_ID 0xFF
/* ********** CMT2300A_CUS_CMT5 registers ********** */
#define CMT2300A_MASK_LMT_CODE 0xC0
/* ********** CMT2300A_CUS_CMT9 registers ********** */
#define CMT2300A_MASK_RSSI_OFFSET_SIGN 0x80
#define CMT2300A_MASK_DIG_CLKDIV 0x1F
/* ********** CMT2300A_CUS_RSSI registers ********** */
#define CMT2300A_MASK_RSSI_OFFSET 0xF8
#define CMT2300A_MASK_RSSI_SLOPE 0x07
/* ********** CMT2300A_CUS_SYS1 registers ********** */
#define CMT2300A_MASK_LMT_VTR 0xC0
#define CMT2300A_MASK_MIXER_BIAS 0x30
#define CMT2300A_MASK_LNA_MODE 0x0C
#define CMT2300A_MASK_LNA_BIAS 0x03
/* ********** CMT2300A_CUS_SYS2 registers ********** */
#define CMT2300A_MASK_LFOSC_RECAL_EN 0x80
#define CMT2300A_MASK_LFOSC_CAL1_EN 0x40
#define CMT2300A_MASK_LFOSC_CAL2_EN 0x20
#define CMT2300A_MASK_RX_TIMER_EN 0x10
#define CMT2300A_MASK_SLEEP_TIMER_EN 0x08
#define CMT2300A_MASK_TX_DC_EN 0x04
#define CMT2300A_MASK_RX_DC_EN 0x02
#define CMT2300A_MASK_DC_PAUSE 0x01
/* ********** CMT2300A_CUS_SYS3 registers ********** */
#define CMT2300A_MASK_SLEEP_BYPASS_EN 0x80
#define CMT2300A_MASK_XTAL_STB_TIME 0x70
#define CMT2300A_MASK_TX_EXIT_STATE 0x0C
#define CMT2300A_MASK_RX_EXIT_STATE 0x03
/* ********** CMT2300A_CUS_SYS4 registers ********** */
#define CMT2300A_MASK_SLEEP_TIMER_M_7_0 0xFF
/* ********** CMT2300A_CUS_SYS5 registers ********** */
#define CMT2300A_MASK_SLEEP_TIMER_M_10_8 0x70
#define CMT2300A_MASK_SLEEP_TIMER_R 0x0F
/* ********** CMT2300A_CUS_SYS6 registers ********** */
#define CMT2300A_MASK_RX_TIMER_T1_M_7_0 0xFF
/* ********** CMT2300A_CUS_SYS7 registers ********** */
#define CMT2300A_MASK_RX_TIMER_T1_M_10_8 0x70
#define CMT2300A_MASK_RX_TIMER_T1_R 0x0F
/* ********** CMT2300A_CUS_SYS8 registers ********** */
#define CMT2300A_MASK_RX_TIMER_T2_M_7_0 0xFF
/* ********** CMT2300A_CUS_SYS9 registers ********** */
#define CMT2300A_MASK_RX_TIMER_T2_M_10_8 0x70
#define CMT2300A_MASK_RX_TIMER_T2_R 0x0F
/* ********** CMT2300A_CUS_SYS10 registers ********** */
#define CMT2300A_MASK_COL_DET_EN 0x80
#define CMT2300A_MASK_COL_OFS_SEL 0x40
#define CMT2300A_MASK_RX_AUTO_EXIT_DIS 0x20
#define CMT2300A_MASK_DOUT_MUTE 0x10
#define CMT2300A_MASK_RX_EXTEND_MODE 0x0F
/* ********** CMT2300A_CUS_SYS11 registers ********** */
#define CMT2300A_MASK_PJD_TH_SEL 0x80
#define CMT2300A_MASK_CCA_INT_SEL 0x60
#define CMT2300A_MASK_RSSI_DET_SEL 0x18
#define CMT2300A_MASK_RSSI_AVG_MODE 0x07
/* ********** CMT2300A_CUS_SYS12 registers ********** */
#define CMT2300A_MASK_PJD_WIN_SEL 0xC0
#define CMT2300A_MASK_CLKOUT_EN 0x20
#define CMT2300A_MASK_CLKOUT_DIV 0x1F
/* ********** CMT2300A_CUS_RF1 registers ********** */
#define CMT2300A_MASK_FREQ_RX_N 0xFF
/* ********** CMT2300A_CUS_RF2 registers ********** */
#define CMT2300A_MASK_FREQ_RX_K_7_0 0xFF
/* ********** CMT2300A_CUS_RF3 registers ********** */
#define CMT2300A_MASK_FREQ_RX_K_15_8 0xFF
/* ********** CMT2300A_CUS_RF4 registers ********** */
#define CMT2300A_MASK_FREQ_PALDO_SEL 0x80
#define CMT2300A_MASK_FREQ_DIVX_CODE 0x70
#define CMT2300A_MASK_FREQ_RX_K_19_16 0x0F
/* ********** CMT2300A_CUS_RF5 registers ********** */
#define CMT2300A_MASK_FREQ_TX_N 0xFF
/* ********** CMT2300A_CUS_RF6 registers ********** */
#define CMT2300A_MASK_FREQ_TX_K_7_0 0xFF
/* ********** CMT2300A_CUS_RF7 registers ********** */
#define CMT2300A_MASK_FREQ_TX_K_15_8 0xFF
/* ********** CMT2300A_CUS_RF8 registers ********** */
#define CMT2300A_MASK_FSK_SWT 0x80
#define CMT2300A_MASK_FREQ_VCO_BANK 0x70
#define CMT2300A_MASK_FREQ_TX_K_19_16 0x0F
/* ********** CMT2300A_CUS_PKT1 registers ********** */
#define CMT2300A_MASK_RX_PREAM_SIZE 0xF8
#define CMT2300A_MASK_PREAM_LENG_UNIT 0x04
#define CMT2300A_MASK_DATA_MODE 0x03
/* CMT2300A_MASK_PREAM_LENG_UNIT options */
#define CMT2300A_PREAM_LENG_UNIT_8_BITS 0x00
#define CMT2300A_PREAM_LENG_UNIT_4_BITS 0x04
/* CMT2300A_MASK_DATA_MODE options */
#define CMT2300A_DATA_MODE_DIRECT 0x00
#define CMT2300A_DATA_MODE_PACKET 0x02
/* ********** CMT2300A_CUS_PKT2 registers ********** */
#define CMT2300A_MASK_TX_PREAM_SIZE_7_0 0xFF
/* ********** CMT2300A_CUS_PKT3 registers ********** */
#define CMT2300A_MASK_TX_PREAM_SIZE_15_8 0xFF
/* ********** CMT2300A_CUS_PKT4 registers ********** */
#define CMT2300A_MASK_PREAM_VALUE 0xFF
/* ********** CMT2300A_CUS_PKT5 registers ********** */
#define CMT2300A_MASK_SYNC_TOL 0x70
#define CMT2300A_MASK_SYNC_SIZE 0x0E
#define CMT2300A_MASK_SYNC_MAN_EN 0x01
/* ********** CMT2300A_CUS_PKT6 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_7_0 0xFF
/* ********** CMT2300A_CUS_PKT7 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_15_8 0xFF
/* ********** CMT2300A_CUS_PKT8 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_23_16 0xFF
/* ********** CMT2300A_CUS_PKT9 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_31_24 0xFF
/* ********** CMT2300A_CUS_PKT10 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_39_32 0xFF
/* ********** CMT2300A_CUS_PKT11 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_47_40 0xFF
/* ********** CMT2300A_CUS_PKT12 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_55_48 0xFF
/* ********** CMT2300A_CUS_PKT13 registers ********** */
#define CMT2300A_MASK_SYNC_VALUE_63_56 0xFF
/* ********** CMT2300A_CUS_PKT14 registers ********** */
#define CMT2300A_MASK_PAYLOAD_LENG_10_8 0x70
#define CMT2300A_MASK_AUTO_ACK_EN 0x08
#define CMT2300A_MASK_NODE_LENG_POS_SEL 0x04
#define CMT2300A_MASK_PAYLOAD_BIT_ORDER 0x02
#define CMT2300A_MASK_PKT_TYPE 0x01
/* CMT2300A_MASK_NODE_LENG_POS_SEL options */
#define CMT2300A_NODE_LENG_FIRST_NODE 0x00
#define CMT2300A_NODE_LENG_FIRST_LENGTH 0x04
/* CMT2300A_MASK_PAYLOAD_BIT_ORDER options */
#define CMT2300A_PAYLOAD_BIT_ORDER_MSB 0x00
#define CMT2300A_PAYLOAD_BIT_ORDER_LSB 0x02
/* CMT2300A_MASK_PKT_TYPE options */
#define CMT2300A_PKT_TYPE_FIXED 0x00
#define CMT2300A_PKT_TYPE_VARIABLE 0x01
/* ********** CMT2300A_CUS_PKT15 registers ********** */
#define CMT2300A_MASK_PAYLOAD_LENG_7_0 0xFF
/* ********** CMT2300A_CUS_PKT16 registers ********** */
#define CMT2300A_MASK_NODE_FREE_EN 0x20
#define CMT2300A_MASK_NODE_ERR_MASK 0x10
#define CMT2300A_MASK_NODE_SIZE 0x0C
#define CMT2300A_MASK_NODE_DET_MODE 0x03
/* CMT2300A_MASK_NODE_DET_MODE options */
#define CMT2300A_NODE_DET_NODE 0x00
#define CMT2300A_NODE_DET_VALUE 0x01
#define CMT2300A_NODE_DET_VALUE_0 0x02
#define CMT2300A_NODE_DET_VALUE_0_1 0x03
/* ********** CMT2300A_CUS_PKT17 registers ********** */
#define CMT2300A_MASK_NODE_VALUE_7_0 0xFF
/* ********** CMT2300A_CUS_PKT18 registers ********** */
#define CMT2300A_MASK_NODE_VALUE_15_8 0xFF
/* ********** CMT2300A_CUS_PKT19 registers ********** */
#define CMT2300A_MASK_NODE_VALUE_23_16 0xFF
/* ********** CMT2300A_CUS_PKT20 registers ********** */
#define CMT2300A_MASK_NODE_VALUE_31_24 0xFF
/* ********** CMT2300A_CUS_PKT21 registers ********** */
#define CMT2300A_MASK_FEC_TYPE 0x80
#define CMT2300A_MASK_FEC_EN 0x40
#define CMT2300A_MASK_CRC_BYTE_SWAP 0x20
#define CMT2300A_MASK_CRC_BIT_INV 0x10
#define CMT2300A_MASK_CRC_RANGE 0x08
#define CMT2300A_MASK_CRC_TYPE 0x06
#define CMT2300A_MASK_CRC_EN 0x01
/* CMT2300A_MASK_CRC_BYTE_SWAP options */
#define CMT2300A_CRC_ORDER_HBYTE 0x00
#define CMT2300A_CRC_ORDER_LBYTE 0x20
/* CMT2300A_MASK_CRC_RANGE options */
#define CMT2300A_CRC_RANGE_PAYLOAD 0x00
#define CMT2300A_CRC_RANGE_DATA 0x08
/* CMT2300A_MASK_CRC_TYPE options */
#define CMT2300A_CRC_TYPE_CCITT16 0x00
#define CMT2300A_CRC_TYPE_IBM16 0x02
#define CMT2300A_CRC_TYPE_ITuint16_t 0x04
/* ********** CMT2300A_CUS_PKT22 registers ********** */
#define CMT2300A_MASK_CRC_SEED_7_0 0xFF
/* ********** CMT2300A_CUS_PKT23 registers ********** */
#define CMT2300A_MASK_CRC_SEED_15_8 0xFF
/* ********** CMT2300A_CUS_PKT24 registers ********** */
#define CMT2300A_MASK_CRC_BIT_ORDER 0x80
#define CMT2300A_MASK_WHITEN_SEED_8_8 0x40
#define CMT2300A_MASK_WHITEN_SEED_TYPE 0x20
#define CMT2300A_MASK_WHITEN_TYPE 0x18
#define CMT2300A_MASK_WHITEN_EN 0x04
#define CMT2300A_MASK_MANCH_TYPE 0x02
#define CMT2300A_MASK_MANCH_EN 0x01
/* CMT2300A_MASK_CRC_BIT_ORDER options */
#define CMT2300A_CRC_BIT_ORDER_MSB 0x00
#define CMT2300A_CRC_BIT_ORDER_LSB 0x80
/* CMT2300A_MASK_WHITEN_SEED_TYPE options */
#define CMT2300A_WHITEN_SEED_TYPE_1 0x00
#define CMT2300A_WHITEN_SEED_TYPE_2 0x20
/* CMT2300A_MASK_WHITEN_TYPE options */
#define CMT2300A_WHITEN_TYPE_PN9_CCITT 0x00
#define CMT2300A_WHITEN_TYPE_PN9_IBM 0x08
#define CMT2300A_WHITEN_TYPE_PN7 0x10
/* CMT2300A_MASK_MANCH_TYPE options */
#define CMT2300A_MANCH_TYPE_ONE_01 0x00
#define CMT2300A_MANCH_TYPE_ONE_10 0x02
/* ********** CMT2300A_CUS_PKT25 registers ********** */
#define CMT2300A_MASK_WHITEN_SEED_7_0 0xFF
/* ********** CMT2300A_CUS_PKT26 registers ********** */
#define CMT2300A_MASK_TX_PREFIX_TYPE 0x03
/* ********** CMT2300A_CUS_PKT27 registers ********** */
#define CMT2300A_MASK_TX_PKT_NUM 0xFF
/* ********** CMT2300A_CUS_PKT28 registers ********** */
#define CMT2300A_MASK_TX_PKT_GAP 0xFF
/* ********** CMT2300A_CUS_PKT29 registers ********** */
#define CMT2300A_MASK_FIFO_AUTO_RES_EN 0x80
#define CMT2300A_MASK_FIFO_TH 0x7F
/* ********** CMT2300A_CUS_MODE_CTL registers ********** */
#define CMT2300A_MASK_CHIP_MODE_SWT 0xFF
/* CMT2300A_MASK_CHIP_MODE_SWT options */
#define CMT2300A_GO_EEPROM 0x01
#define CMT2300A_GO_STBY 0x02
#define CMT2300A_GO_RFS 0x04
#define CMT2300A_GO_RX 0x08
#define CMT2300A_GO_SLEEP 0x10
#define CMT2300A_GO_TFS 0x20
#define CMT2300A_GO_TX 0x40
#define CMT2300A_GO_SWITCH 0x80
/* ********** CMT2300A_CUS_MODE_STA registers ********** */
#define CMT2300A_MASK_RSTN_IN_EN 0x20
#define CMT2300A_MASK_CFG_RETAIN 0x10
#define CMT2300A_MASK_CHIP_MODE_STA 0x0F
/* CMT2300A_MASK_CHIP_MODE_STA options */
#define CMT2300A_STA_IDLE 0x00
#define CMT2300A_STA_SLEEP 0x01
#define CMT2300A_STA_STBY 0x02
#define CMT2300A_STA_RFS 0x03
#define CMT2300A_STA_TFS 0x04
#define CMT2300A_STA_RX 0x05
#define CMT2300A_STA_TX 0x06
#define CMT2300A_STA_EEPROM 0x07
#define CMT2300A_STA_ERROR 0x08
#define CMT2300A_STA_CAL 0x09
/* ********** CMT2300A_CUS_EN_CTL registers ********** */
#define CMT2300A_MASK_LOCKING_EN 0x20
/* ********** CMT2300A_CUS_FREQ_CHNL registers ********** */
#define CMT2300A_MASK_FH_CHANNEL 0xFF
/* ********** CMT2300A_CUS_FREQ_OFS registers ********** */
#define CMT2300A_MASK_FH_OFFSET 0xFF
/* ********** CMT2300A_CUS_IO_SEL registers ********** */
#define CMT2300A_MASK_GPIO4_SEL 0xC0
#define CMT2300A_MASK_GPIO3_SEL 0x30
#define CMT2300A_MASK_GPIO2_SEL 0x0C
#define CMT2300A_MASK_GPIO1_SEL 0x03
/* CMT2300A_MASK_GPIO4_SEL options */
#define CMT2300A_GPIO4_SEL_RSTIN 0x00
#define CMT2300A_GPIO4_SEL_INT1 0x40
#define CMT2300A_GPIO4_SEL_DOUT 0x80
#define CMT2300A_GPIO4_SEL_DCLK 0xC0
/* CMT2300A_MASK_GPIO3_SEL options */
#define CMT2300A_GPIO3_SEL_CLKO 0x00
#define CMT2300A_GPIO3_SEL_DOUT 0x10
#define CMT2300A_GPIO3_SEL_DIN 0x10
#define CMT2300A_GPIO3_SEL_INT2 0x20
#define CMT2300A_GPIO3_SEL_DCLK 0x30
/* CMT2300A_MASK_GPIO2_SEL options */
#define CMT2300A_GPIO2_SEL_INT1 0x00
#define CMT2300A_GPIO2_SEL_INT2 0x04
#define CMT2300A_GPIO2_SEL_DOUT 0x08
#define CMT2300A_GPIO2_SEL_DIN 0x08
#define CMT2300A_GPIO2_SEL_DCLK 0x0C
/* CMT2300A_MASK_GPIO1_SEL options */
#define CMT2300A_GPIO1_SEL_DOUT 0x00
#define CMT2300A_GPIO1_SEL_DIN 0x00
#define CMT2300A_GPIO1_SEL_INT1 0x01
#define CMT2300A_GPIO1_SEL_INT2 0x02
#define CMT2300A_GPIO1_SEL_DCLK 0x03
/* ********** CMT2300A_CUS_INT1_CTL registers ********** */
#define CMT2300A_MASK_RF_SWT1_EN 0x80
#define CMT2300A_MASK_RF_SWT2_EN 0x40
#define CMT2300A_MASK_INT_POLAR 0x20
#define CMT2300A_MASK_INT1_SEL 0x1F
/* CMT2300A_MASK_INT_POLAR options */
#define CMT2300A_INT_POLAR_SEL_0 0x00
#define CMT2300A_INT_POLAR_SEL_1 0x20
/* CMT2300A_MASK_INT1_SEL options */
#define CMT2300A_INT_SEL_RX_ACTIVE 0x00
#define CMT2300A_INT_SEL_TX_ACTIVE 0x01
#define CMT2300A_INT_SEL_RSSI_VLD 0x02
#define CMT2300A_INT_SEL_PREAM_OK 0x03
#define CMT2300A_INT_SEL_SYNC_OK 0x04
#define CMT2300A_INT_SEL_NODE_OK 0x05
#define CMT2300A_INT_SEL_CRC_OK 0x06
#define CMT2300A_INT_SEL_PKT_OK 0x07
#define CMT2300A_INT_SEL_SL_TMO 0x08
#define CMT2300A_INT_SEL_RX_TMO 0x09
#define CMT2300A_INT_SEL_TX_DONE 0x0A
#define CMT2300A_INT_SEL_RX_FIFO_NMTY 0x0B
#define CMT2300A_INT_SEL_RX_FIFO_TH 0x0C
#define CMT2300A_INT_SEL_RX_FIFO_FULL 0x0D
#define CMT2300A_INT_SEL_RX_FIFO_WBYTE 0x0E
#define CMT2300A_INT_SEL_RX_FIFO_OVF 0x0F
#define CMT2300A_INT_SEL_TX_FIFO_NMTY 0x10
#define CMT2300A_INT_SEL_TX_FIFO_TH 0x11
#define CMT2300A_INT_SEL_TX_FIFO_FULL 0x12
#define CMT2300A_INT_SEL_STATE_IS_STBY 0x13
#define CMT2300A_INT_SEL_STATE_IS_FS 0x14
#define CMT2300A_INT_SEL_STATE_IS_RX 0x15
#define CMT2300A_INT_SEL_STATE_IS_TX 0x16
#define CMT2300A_INT_SEL_LED 0x17
#define CMT2300A_INT_SEL_TRX_ACTIVE 0x18
#define CMT2300A_INT_SEL_PKT_DONE 0x19
/* ********** CMT2300A_CUS_INT2_CTL registers ********** */
#define CMT2300A_MASK_LFOSC_OUT_EN 0x40
#define CMT2300A_MASK_TX_DIN_INV 0x20
#define CMT2300A_MASK_INT2_SEL 0x1F
/* ********** CMT2300A_CUS_INT_EN registers ********** */
#define CMT2300A_MASK_SL_TMO_EN 0x80
#define CMT2300A_MASK_RX_TMO_EN 0x40
#define CMT2300A_MASK_TX_DONE_EN 0x20
#define CMT2300A_MASK_PREAM_OK_EN 0x10
#define CMT2300A_MASK_SYNC_OK_EN 0x08
#define CMT2300A_MASK_NODE_OK_EN 0x04
#define CMT2300A_MASK_CRC_OK_EN 0x02
#define CMT2300A_MASK_PKT_DONE_EN 0x01
/* ********** CMT2300A_CUS_FIFO_CTL registers ********** */
#define CMT2300A_MASK_TX_DIN_EN 0x80
#define CMT2300A_MASK_TX_DIN_SEL 0x60
#define CMT2300A_MASK_FIFO_AUTO_CLR_DIS 0x10
#define CMT2300A_MASK_FIFO_TX_RD_EN 0x08
#define CMT2300A_MASK_FIFO_RX_TX_SEL 0x04
#define CMT2300A_MASK_FIFO_MERGE_EN 0x02
#define CMT2300A_MASK_SPI_FIFO_RD_WR_SEL 0x01
/* CMT2300A_MASK_TX_DIN_SEL options */
#define CMT2300A_TX_DIN_SEL_GPIO1 0x00
#define CMT2300A_TX_DIN_SEL_GPIO2 0x20
#define CMT2300A_TX_DIN_SEL_GPIO3 0x40
/* ********** CMT2300A_CUS_INT_CLR1 registers ********** */
#define CMT2300A_MASK_SL_TMO_FLG 0x20
#define CMT2300A_MASK_RX_TMO_FLG 0x10
#define CMT2300A_MASK_TX_DONE_FLG 0x08
#define CMT2300A_MASK_TX_DONE_CLR 0x04
#define CMT2300A_MASK_SL_TMO_CLR 0x02
#define CMT2300A_MASK_RX_TMO_CLR 0x01
/* ********** CMT2300A_CUS_INT_CLR2 registers ********** */
#define CMT2300A_MASK_LBD_CLR 0x20
#define CMT2300A_MASK_PREAM_OK_CLR 0x10
#define CMT2300A_MASK_SYNC_OK_CLR 0x08
#define CMT2300A_MASK_NODE_OK_CLR 0x04
#define CMT2300A_MASK_CRC_OK_CLR 0x02
#define CMT2300A_MASK_PKT_DONE_CLR 0x01
/* ********** CMT2300A_CUS_FIFO_CLR registers ********** */
#define CMT2300A_MASK_FIFO_RESTORE 0x04
#define CMT2300A_MASK_FIFO_CLR_RX 0x02
#define CMT2300A_MASK_FIFO_CLR_TX 0x01
/* ********** CMT2300A_CUS_INT_FLAG registers ********** */
#define CMT2300A_MASK_LBD_FLG 0x80
#define CMT2300A_MASK_COL_ERR_FLG 0x40
#define CMT2300A_MASK_PKT_ERR_FLG 0x20
#define CMT2300A_MASK_PREAM_OK_FLG 0x10
#define CMT2300A_MASK_SYNC_OK_FLG 0x08
#define CMT2300A_MASK_NODE_OK_FLG 0x04
#define CMT2300A_MASK_CRC_OK_FLG 0x02
#define CMT2300A_MASK_PKT_OK_FLG 0x01
/* ********** CMT2300A_CUS_FIFO_FLAG registers ********** */
#define CMT2300A_MASK_RX_FIFO_FULL_FLG 0x40
#define CMT2300A_MASK_RX_FIFO_NMTY_FLG 0x20
#define CMT2300A_MASK_RX_FIFO_TH_FLG 0x10
#define CMT2300A_MASK_RX_FIFO_OVF_FLG 0x08
#define CMT2300A_MASK_TX_FIFO_FULL_FLG 0x04
#define CMT2300A_MASK_TX_FIFO_NMTY_FLG 0x02
#define CMT2300A_MASK_TX_FIFO_TH_FLG 0x01
/* ********** CMT2300A_CUS_RSSI_CODE registers ********** */
#define CMT2300A_MASK_RSSI_CODE 0xFF
/* ********** CMT2300A_CUS_RSSI_DBM registers ********** */
#define CMT2300A_MASK_RSSI_DBM 0xFF
/* ********** CMT2300A_CUS_LBD_RESULT registers ********** */
#define CMT2300A_MASK_LBD_RESULT 0xFF
#endif

View File

@ -1,76 +0,0 @@
/*
* 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);
}

View File

@ -1,51 +0,0 @@
/*
* 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

View File

@ -1,214 +0,0 @@
/*
;---------------------------------------
; CMT2300A Configuration File
; Generated by CMOSTEK RFPDK 1.46
; 2023.03.17 23:16
;---------------------------------------
; Mode = Advanced
; Part Number = CMT2300A
; Frequency = 860.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_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_860[CMT2300A_CMT_BANK_SIZE] = {
0x00,
0x66,
0xEC,
0x1C,
0x70,
0x80,
0x14,
0x08,
0x11,
0x02,
0x02,
0x00,
};
/* [System Bank] */
static uint8_t g_cmt2300aSystemBank_860[CMT2300A_SYSTEM_BANK_SIZE] = {
0xAE,
0xE0,
0x35,
0x00,
0x00,
0xF4,
0x10,
0xE2,
0x42,
0x20,
0x0C,
0x81,
};
/* [Frequency Bank] 860 MHz */
static uint8_t g_cmt2300aFrequencyBank_860[CMT2300A_FREQUENCY_BANK_SIZE] = {
0x42,
0x32,
0xCF,
0x82,
0x42,
0x27,
0x76,
0x12,
};
/* [Data Rate Bank] */
static uint8_t g_cmt2300aDataRateBank_860[CMT2300A_DATA_RATE_BANK_SIZE] = {
0xA6,
0xC9,
0x20,
0x20,
0xD2,
0x35,
0x0C,
0x0A,
0x9F,
0x4B,
0x29,
0x29,
0xC0,
0x14,
0x05,
0x53,
0x10,
0x00,
0xB4,
0x00,
0x00,
0x01,
0x00,
0x00,
};
/* [Baseband Bank] - EU */
static uint8_t g_cmt2300aBasebandBank_860[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_860[CMT2300A_TX_BANK_SIZE] = {
0x70,
0x4D,
0x06,
0x00,
0x07,
0x50,
0x00,
0x53,
0x09,
0x3F,
0x7F,
};
#endif

View File

@ -1,214 +0,0 @@
/*
;---------------------------------------
; 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

View File

@ -1,330 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2023-2024 Thomas Basler and others
*/
#include "cmt2300wrapper.h"
#include "cmt2300a.h"
#include "cmt2300a_params_860.h"
#include "cmt2300a_params_900.h"
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;
_pin_cs = pin_cs;
_pin_fcs = pin_fcs;
_spi_speed = spi_speed;
}
bool CMT2300A::begin(void)
{
return _init_pins() && _init_radio();
}
bool CMT2300A::isChipConnected()
{
return CMT2300A_IsExist();
}
bool CMT2300A::startListening(void)
{
CMT2300A_GoStby();
CMT2300A_ClearInterruptFlags();
/* Must clear FIFO after enable SPI to read or write the FIFO */
CMT2300A_EnableReadFifo();
CMT2300A_ClearRxFifo();
if (!CMT2300A_GoRx()) {
return false;
} else {
return true;
}
}
bool CMT2300A::stopListening(void)
{
CMT2300A_ClearInterruptFlags();
return CMT2300A_GoSleep();
}
bool CMT2300A::available(void)
{
return (
CMT2300A_MASK_PREAM_OK_FLG |
CMT2300A_MASK_SYNC_OK_FLG |
CMT2300A_MASK_CRC_OK_FLG |
CMT2300A_MASK_PKT_OK_FLG
) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG);
}
void CMT2300A::read(void* buf, const uint8_t len)
{
// Fetch the payload
CMT2300A_ReadFifo(static_cast<uint8_t*>(buf), len);
CMT2300A_ClearInterruptFlags();
}
bool CMT2300A::write(const uint8_t* buf, const uint8_t len)
{
CMT2300A_GoStby();
CMT2300A_ClearInterruptFlags();
/* Must clear FIFO after enable SPI to read or write the FIFO */
CMT2300A_EnableWriteFifo();
CMT2300A_ClearTxFifo();
CMT2300A_WriteReg(CMT2300A_CUS_PKT15, len); // set Tx length
/* The length need be smaller than 32 */
CMT2300A_WriteFifo(buf, len);
if (!(CMT2300A_ReadReg(CMT2300A_CUS_FIFO_FLAG) & CMT2300A_MASK_TX_FIFO_NMTY_FLG)) {
return false;
}
if (!CMT2300A_GoTx()) {
return false;
}
uint32_t timer = millis();
while (!(CMT2300A_MASK_TX_DONE_FLG & CMT2300A_ReadReg(CMT2300A_CUS_INT_CLR1))) {
if (millis() - timer > 95) {
return false;
}
}
CMT2300A_ClearInterruptFlags();
CMT2300A_GoSleep();
return true;
}
void CMT2300A::setChannel(const uint8_t channel)
{
CMT2300A_SetFrequencyChannel(channel);
}
uint8_t CMT2300A::getChannel(void)
{
return CMT2300A_ReadReg(CMT2300A_CUS_FREQ_CHNL);
}
uint8_t CMT2300A::getDynamicPayloadSize(void)
{
uint8_t result;
CMT2300A_ReadFifo(&result, 1); // first byte in FiFo is length
return result;
}
int CMT2300A::getRssiDBm()
{
return CMT2300A_GetRssiDBm();
}
bool CMT2300A::setPALevel(const int8_t level)
{
uint16_t Tx_dBm_word;
switch (level) {
// for TRx Matching Network Type: 20 dBm
case -10:
Tx_dBm_word = 0x0501;
break;
case -9:
Tx_dBm_word = 0x0601;
break;
case -8:
Tx_dBm_word = 0x0701;
break;
case -7:
Tx_dBm_word = 0x0801;
break;
case -6:
Tx_dBm_word = 0x0901;
break;
case -5:
Tx_dBm_word = 0x0A01;
break;
case -4:
Tx_dBm_word = 0x0B01;
break;
case -3:
Tx_dBm_word = 0x0C01;
break;
case -2:
Tx_dBm_word = 0x0D01;
break;
case -1:
Tx_dBm_word = 0x0E01;
break;
case 0:
Tx_dBm_word = 0x1002;
break;
case 1:
Tx_dBm_word = 0x1302;
break;
case 2:
Tx_dBm_word = 0x1602;
break;
case 3:
Tx_dBm_word = 0x1902;
break;
case 4:
Tx_dBm_word = 0x1C02;
break;
case 5:
Tx_dBm_word = 0x1F03;
break;
case 6:
Tx_dBm_word = 0x2403;
break;
case 7:
Tx_dBm_word = 0x2804;
break;
case 8:
Tx_dBm_word = 0x2D04;
break;
case 9:
Tx_dBm_word = 0x3305;
break;
case 10:
Tx_dBm_word = 0x3906;
break;
case 11:
Tx_dBm_word = 0x4107;
break;
case 12:
Tx_dBm_word = 0x4908;
break;
case 13:
Tx_dBm_word = 0x5309;
break;
case 14:
Tx_dBm_word = 0x5E0B;
break;
case 15:
Tx_dBm_word = 0x6C0C;
break;
case 16:
Tx_dBm_word = 0x7D0C;
break;
// the following values require the double bit:
case 17:
Tx_dBm_word = 0x4A0C;
break;
case 18:
Tx_dBm_word = 0x580F;
break;
case 19:
Tx_dBm_word = 0x6B12;
break;
case 20:
Tx_dBm_word = 0x8A18;
break;
default:
return false;
}
if (level > 16) { // set bit for double Tx value
CMT2300A_WriteReg(CMT2300A_CUS_CMT4, CMT2300A_ReadReg(CMT2300A_CUS_CMT4) | 0x01); // set bit0
} else {
CMT2300A_WriteReg(CMT2300A_CUS_CMT4, CMT2300A_ReadReg(CMT2300A_CUS_CMT4) & 0xFE); // reset bit0
}
CMT2300A_WriteReg(CMT2300A_CUS_TX8, Tx_dBm_word >> 8);
CMT2300A_WriteReg(CMT2300A_CUS_TX9, Tx_dBm_word & 0xFF);
return true;
}
bool CMT2300A::rxFifoAvailable()
{
return (
CMT2300A_MASK_PKT_OK_FLG
) & 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();
}
bool CMT2300A::_init_pins()
{
CMT2300A_InitSpi(_pin_sdio, _pin_clk, _pin_cs, _pin_fcs, _spi_speed);
return true; // assuming pins are connected properly
}
bool CMT2300A::_init_radio()
{
if (!CMT2300A_Init()) {
return false;
}
/* config registers */
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;
tmp = (~0x07) & CMT2300A_ReadReg(CMT2300A_CUS_CMT10);
CMT2300A_WriteReg(CMT2300A_CUS_CMT10, tmp | 0x02);
/* Config GPIOs */
CMT2300A_ConfigGpio(
CMT2300A_GPIO2_SEL_INT1 | CMT2300A_GPIO3_SEL_INT2);
/* Config interrupt */
CMT2300A_ConfigInterrupt(
CMT2300A_INT_SEL_TX_DONE, /* Config INT1 */
CMT2300A_INT_SEL_PKT_OK /* Config INT2 */
);
/* Enable interrupt */
CMT2300A_EnableInterrupt(
CMT2300A_MASK_TX_DONE_EN | CMT2300A_MASK_PREAM_OK_EN | CMT2300A_MASK_SYNC_OK_EN | CMT2300A_MASK_CRC_OK_EN | CMT2300A_MASK_PKT_DONE_EN);
CMT2300A_SetFrequencyStep(FH_OFFSET); // set FH_OFFSET (frequency = base freq + 2.5kHz*FH_OFFSET*FH_CHANNEL)
/* Use a single 64-byte FIFO for either Tx or Rx */
CMT2300A_EnableFifoMerge(true);
/* Go to sleep for configuration to take effect */
if (!CMT2300A_GoSleep()) {
return false; // CMT2300A not switched to sleep mode!
}
return true;
}

View File

@ -1,138 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#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 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(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);
/**
* Checks if the chip is connected to the SPI bus
*/
bool isChipConnected();
bool startListening(void);
bool stopListening(void);
/**
* Check whether there are bytes available to be read
* @code
* if(radio.available()){
* radio.read(&data,sizeof(data));
* }
* @endcode
*
* @see available(uint8_t*)
*
* @return True if there is a payload available, false if none is
*/
bool available(void);
/**
* Read payload data from the RX FIFO buffer(s).
*
* The length of data read is usually the next available payload's length
* @see
* - getDynamicPayloadSize()
*
* @note I specifically chose `void*` as a data type to make it easier
* for beginners to use. No casting needed.
*
* @param buf Pointer to a buffer where the data should be written
* @param len Maximum number of bytes to read into the buffer. This
* value should match the length of the object referenced using the
* `buf` parameter. The absolute maximum number of bytes that can be read
* 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, const 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(const uint8_t channel);
/**
* Get RF communication channel
* @return The currently configured RF Channel
*/
uint8_t getChannel(void);
/**
* Get Dynamic Payload Size
*
* For dynamic payloads, this pulls the size of the payload off
* the chip
*
* @return Payload length of last-received dynamic payload
*/
uint8_t getDynamicPayloadSize(void);
int getRssiDBm();
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.
*/
void flush_rx(void);
private:
/**
* initialize the GPIO pins
*/
bool _init_pins();
/**
* initialize radio.
* @warning This function assumes the SPI bus object's begin() method has been
* previously called.
*/
bool _init_radio();
int8_t _pin_sdio;
int8_t _pin_clk;
int8_t _pin_cs;
int8_t _pin_fcs;
uint32_t _spi_speed;
FrequencyBand_t _frequencyBand = FrequencyBand_t::BAND_860;
};

View File

@ -1,155 +0,0 @@
#include "cmt_spi3.h"
#include <Arduino.h>
#include <driver/spi_master.h>
#include <SpiManager.h>
SemaphoreHandle_t paramLock = NULL;
#define SPI_PARAM_LOCK() \
do { \
} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
static void IRAM_ATTR pre_cb(spi_transaction_t *trans) {
gpio_set_level(*reinterpret_cast<gpio_num_t*>(trans->user), 0);
}
static void IRAM_ATTR post_cb(spi_transaction_t *trans) {
gpio_set_level(*reinterpret_cast<gpio_num_t*>(trans->user), 1);
}
spi_device_handle_t spi;
gpio_num_t cs_reg, cs_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 int32_t spi_speed)
{
paramLock = xSemaphoreCreateMutex();
auto bus_config = std::make_shared<SpiBusConfig>(
static_cast<gpio_num_t>(pin_sdio),
GPIO_NUM_NC,
static_cast<gpio_num_t>(pin_clk)
);
spi_device_interface_config_t device_config {
.command_bits = 0, // set by transactions individually
.address_bits = 0, // set by transactions individually
.dummy_bits = 0,
.mode = 0, // SPI mode 0
.duty_cycle_pos = 0,
.cs_ena_pretrans = 2, // only 1 pre and post cycle would be required for register access
.cs_ena_posttrans = static_cast<uint8_t>(2 * spi_speed / 1000000), // >2 us
.clock_speed_hz = spi_speed,
.input_delay_ns = 0,
.spics_io_num = -1, // CS handled by callbacks
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
.queue_size = 1,
.pre_cb = pre_cb,
.post_cb = post_cb,
};
spi = SpiManagerInst.alloc_device("", bus_config, device_config);
if (!spi)
ESP_ERROR_CHECK(ESP_FAIL);
cs_reg = static_cast<gpio_num_t>(pin_cs);
ESP_ERROR_CHECK(gpio_reset_pin(cs_reg));
ESP_ERROR_CHECK(gpio_set_level(cs_reg, 1));
ESP_ERROR_CHECK(gpio_set_direction(cs_reg, GPIO_MODE_OUTPUT));
cs_fifo = static_cast<gpio_num_t>(pin_fcs);
ESP_ERROR_CHECK(gpio_reset_pin(cs_fifo));
ESP_ERROR_CHECK(gpio_set_level(cs_fifo, 1));
ESP_ERROR_CHECK(gpio_set_direction(cs_fifo, GPIO_MODE_OUTPUT));
}
void cmt_spi3_write(const uint8_t addr, const uint8_t data)
{
spi_transaction_ext_t trans {
.base {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = 0,
.addr = addr,
.length = 8,
.rxlength = 0,
.user = &cs_reg, // CS for register access
.tx_buffer = &data,
.rx_buffer = nullptr,
},
.command_bits = 1,
.address_bits = 7,
.dummy_bits = 0,
};
SPI_PARAM_LOCK();
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, reinterpret_cast<spi_transaction_t*>(&trans)));
SPI_PARAM_UNLOCK();
}
uint8_t cmt_spi3_read(const uint8_t addr)
{
uint8_t data;
spi_transaction_ext_t trans {
.base {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.cmd = 1,
.addr = addr,
.length = 0,
.rxlength = 8,
.user = &cs_reg, // CS for register access
.tx_buffer = nullptr,
.rx_buffer = &data,
},
.command_bits = 1,
.address_bits = 7,
.dummy_bits = 0,
};
SPI_PARAM_LOCK();
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, reinterpret_cast<spi_transaction_t*>(&trans)));
SPI_PARAM_UNLOCK();
return data;
}
void cmt_spi3_write_fifo(const uint8_t* buf, const uint16_t len)
{
spi_transaction_t trans {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = 8,
.rxlength = 0,
.user = &cs_fifo, // CS for FIFO access
.tx_buffer = nullptr,
.rx_buffer = nullptr,
};
SPI_PARAM_LOCK();
spi_device_acquire_bus(spi, portMAX_DELAY);
for (uint8_t i = 0; i < len; i++) {
trans.tx_buffer = buf + i;
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &trans));
}
spi_device_release_bus(spi);
SPI_PARAM_UNLOCK();
}
void cmt_spi3_read_fifo(uint8_t* buf, const uint16_t len)
{
spi_transaction_t trans {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = 0,
.rxlength = 8,
.user = &cs_fifo, // CS for FIFO access
.tx_buffer = nullptr,
.rx_buffer = nullptr,
};
SPI_PARAM_LOCK();
spi_device_acquire_bus(spi, portMAX_DELAY);
for (uint8_t i = 0; i < len; i++) {
trans.rx_buffer = buf + i;
ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &trans));
}
spi_device_release_bus(spi);
SPI_PARAM_UNLOCK();
}

View File

@ -1,22 +0,0 @@
#ifndef __CMT_SPI3_H
#define __CMT_SPI3_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
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 int32_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);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,57 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2024 Thomas Basler and others
*/
#include "CpuTemperature.h"
#include <Arduino.h>
#if defined(CONFIG_IDF_TARGET_ESP32)
// there is no official API available on the original ESP32
extern "C" {
uint8_t temprature_sens_read();
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
#include "driver/temp_sensor.h"
#endif
CpuTemperatureClass CpuTemperature;
float CpuTemperatureClass::read()
{
#ifdef CONFIG_IDF_TARGET_ESP32S2
// Disabling temperature reading for ESP32-S2 models as it might lead to WDT resets.
// See: https://github.com/espressif/esp-idf/issues/8088
return NAN;
#endif
std::lock_guard<std::mutex> lock(_mutex);
float temperature = NAN;
bool success = false;
#if defined(CONFIG_IDF_TARGET_ESP32)
uint8_t raw = temprature_sens_read();
ESP_LOGV(TAG, "Raw temperature value: %d", raw);
temperature = (raw - 32) / 1.8f;
success = (raw != 128);
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
temp_sensor_set_config(tsens);
temp_sensor_start();
#if defined(CONFIG_IDF_TARGET_ESP32S3) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 3))
#error \
"ESP32-S3 internal temperature sensor requires ESP IDF V4.4.3 or higher. See https://github.com/esphome/issues/issues/4271"
#endif
esp_err_t result = temp_sensor_read_celsius(&temperature);
temp_sensor_stop();
success = (result == ESP_OK);
#endif
if (success && std::isfinite(temperature)) {
return temperature;
} else {
ESP_LOGD(TAG, "Ignoring invalid temperature (success=%d, value=%.1f)", success, temperature);
return NAN;
}
}

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
class CpuTemperatureClass {
public:
float read();
private:
std::mutex _mutex;
};
extern CpuTemperatureClass CpuTemperature;

View File

@ -1,3 +0,0 @@
serge-sans-paille <sguelton@quarkslab.com>
Jérôme Dumesnil <jerome.dumesnil@gmail.com>
Chris Beck <chbeck@tesla.com>

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 Quarkslab
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,245 +0,0 @@
Frozen
######
.. image:: https://travis-ci.org/serge-sans-paille/frozen.svg?branch=master
:target: https://travis-ci.org/serge-sans-paille/frozen
Header-only library that provides 0 cost initialization for immutable containers, fixed-size containers, and various algorithms.
Frozen provides:
- immutable (a.k.a. frozen), ``constexpr``-compatible versions of ``std::set``,
``std::unordered_set``, ``std::map`` and ``std::unordered_map``.
- fixed-capacity, ``constinit``-compatible versions of ``std::map`` and
``std::unordered_map`` with immutable, compile-time selected keys mapped
to mutable values.
- 0-cost initialization version of ``std::search`` for frozen needles using
Boyer-Moore or Knuth-Morris-Pratt algorithms.
The ``unordered_*`` containers are guaranteed *perfect* (a.k.a. no hash
collision) and the extra storage is linear with respect to the number of keys.
Once initialized, the container keys cannot be updated, and in exchange, lookups
are faster. And initialization is free when ``constexpr`` or ``constinit`` is
used :-).
Installation
------------
Just copy the ``include/frozen`` directory somewhere and points to it using the ``-I`` flag. Alternatively, using CMake:
.. code:: sh
> mkdir build
> cd build
> cmake -D CMAKE_BUILD_TYPE=Release ..
> make install
Installation via CMake populates configuration files into the ``/usr/local/share``
directory which can be consumed by CMake's ``find_package`` instrinsic function.
Requirements
------------
A C++ compiler that supports C++14. Clang version 5 is a good pick, GCC version
6 lags behind in terms of ``constexpr`` compilation time (At least on my
setup), but compiles correctly. Visual Studio 2017 also works correctly!
Note that gcc 5 isn't supported. (Here's an `old compat branch`_ where a small amount of stuff was ported.)
.. _old compat branch: https://github.com/cbeck88/frozen/tree/gcc5-support
Usage
-----
Compiled with ``-std=c++14`` flag:
.. code:: C++
#include <frozen/set.h>
constexpr frozen::set<int, 4> some_ints = {1,2,3,5};
constexpr bool letitgo = some_ints.count(8);
extern int n;
bool letitgoooooo = some_ints.count(n);
As the constructor and some methods are ``constexpr``, it's also possible to write weird stuff like:
.. code:: C++
#include <frozen/set.h>
template<std::size_t N>
std::enable_if_t< frozen::set<int, 3>{{1,11,111}}.count(N), int> foo();
String support is built-in:
.. code:: C++
#include <frozen/unordered_map.h>
#include <frozen/string.h>
constexpr frozen::unordered_map<frozen::string, int, 2> olaf = {
{"19", 19},
{"31", 31},
};
constexpr auto val = olaf.at("19");
The associative containers have different functionality with and without ``constexpr``.
With ``constexpr``, frozen maps have immutable keys and values. Without ``constexpr``, the
values can be updated in runtime (the keys, however, remain immutable):
.. code:: C++
#include <frozen/unordered_map.h>
#include <frozen/string.h>
static constinit frozen::unordered_map<frozen::string, frozen::string, 2> voice = {
{"Anna", "???"},
{"Elsa", "???"}
};
int main() {
voice.at("Anna") = "Kristen";
voice.at("Elsa") = "Idina";
}
You may also prefer a slightly more DRY initialization syntax:
.. code:: C++
#include <frozen/set.h>
constexpr auto some_ints = frozen::make_set<int>({1,2,3,5});
There are similar ``make_X`` functions for all frozen containers.
Exception Handling
------------------
For compatibility with STL's API, Frozen may eventually throw exceptions, as in
``frozen::map::at``. If you build your code without exception support, or
define the ``FROZEN_NO_EXCEPTIONS`` macro variable, they will be turned into an
``std::abort``.
Extending
---------
Just like the regular C++14 container, you can specialize the hash function,
the key equality comparator for ``unordered_*`` containers, and the comparison
functions for the ordered version.
It's also possible to specialize the ``frozen::elsa`` structure used for
hashing. Note that unlike `std::hash`, the hasher also takes a seed in addition
to the value being hashed.
.. code:: C++
template <class T> struct elsa {
// in case of collisions, different seeds are tried
constexpr std::size_t operator()(T const &value, std::size_t seed) const;
};
Ideally, the hash function should have nice statistical properties like *pairwise-independence*:
If ``x`` and ``y`` are different values, the chance that ``elsa<T>{}(x, seed) == elsa<T>{}(y, seed)``
should be very low for a random value of ``seed``.
Note that frozen always ultimately produces a perfect hash function, and you will always have ``O(1)``
lookup with frozen. It's just that if the input hasher performs poorly, the search will take longer and
your project will take longer to compile.
Troubleshooting
---------------
If you hit a message like this:
.. code:: none
[...]
note: constexpr evaluation hit maximum step limit; possible infinite loop?
Then either you've got a very big container and you should increase Clang's
thresholds, using ``-fconstexpr-steps=1000000000`` for instance, or the hash
functions used by frozen do not suit your data, and you should change them, as
in the following:
.. code:: c++
struct olaf {
constexpr std::size_t operator()(frozen::string const &value, std::size_t seed) const { return seed ^ value[0];}
};
constexpr frozen::unordered_set<frozen::string, 2, olaf/*custom hash*/> hans = { "a", "b" };
Tests and Benchmarks
--------------------
Using hand-written Makefiles crafted with love and care:
.. code:: sh
> # running tests
> make -C tests check
> # running benchmarks
> make -C benchmarks GOOGLE_BENCHMARK_PREFIX=<GOOGLE-BENCHMARK_INSTALL_DIR>
Using CMake to generate a static configuration build system:
.. code:: sh
> mkdir build
> cd build
> cmake -D CMAKE_BUILD_TYPE=Release \
-D frozen.benchmark=ON \
-G <"Unix Makefiles" or "Ninja"> ..
> # building the tests and benchmarks...
> make # ... with make
> ninja # ... with ninja
> cmake --build . # ... with cmake
> # running the tests...
> make test # ... with make
> ninja test # ... with ninja
> cmake --build . --target test # ... with cmake
> ctest # ... with ctest
> # running the benchmarks...
> make benchmark # ... with make
> ninja benchmark # ... with ninja
> cmake --build . --target benchmark # ... with cmake
Using CMake to generate an IDE build system with test and benchmark targets
.. code:: sh
> mkdir build
> cd build
> cmake -D frozen.benchmark=ON -G <"Xcode" or "Visual Studio 15 2017"> ..
> # using cmake to drive the IDE build, test, and benchmark
> cmake --build . --config Release
> cmake --build . --target test
> cmake --build . --target benchmark
Credits
-------
The perfect hashing is strongly inspired by the blog post `Throw away the keys:
Easy, Minimal Perfect Hashing <http://stevehanov.ca/blog/index.php?id=119>`_.
Thanks a lot to Jérôme Dumesnil for his high-quality reviews, and to Chris Beck
for his contributions on perfect hashing.
Contact
-------
Serge sans Paille ``<serge.guelton@telecom-bretagne.eu>``

View File

@ -1,12 +0,0 @@
target_sources(frozen-headers INTERFACE
"${prefix}/frozen/algorithm.h"
"${prefix}/frozen/map.h"
"${prefix}/frozen/random.h"
"${prefix}/frozen/set.h"
"${prefix}/frozen/string.h"
"${prefix}/frozen/unordered_map.h"
"${prefix}/frozen/unordered_set.h"
"${prefix}/frozen/bits/algorithms.h"
"${prefix}/frozen/bits/basic_types.h"
"${prefix}/frozen/bits/elsa.h"
"${prefix}/frozen/bits/pmh.h")

Some files were not shown because too many files have changed in this diff Show More