OpenDTU-old/lib/Hoymiles/src/HoymilesRadio.cpp
helgeerbe d494810975
merge V23.12.16 (#556)
* Optimize Sun data calculation

* Remove not required enum

* Split config struct into different sub structs

* Feature: Allow configuration of LWT QoS

* Made resetreason methods static

* Feature: Implement offset cache for "YieldDay"

Thanks to @broth-itk for the idea!
Fix: #1258 #1397

* Add Esp32-Stick-PoE-A

* remove broken LilyGO_T_ETH_POE config, use device profile instead

* Feature: High resolution Icon and PWA (Progressive Web App) functionality

Fix: #1289

* webapp: Update dependencies

* Initialize TaskScheduler

* Migrate SunPosition to TaskScheduler

* Migrate Datastore to TaskScheduler

* Migrate MqttHandleInverterTotal to TaskSchedule

* Migrate MqttHandleHass to TaskScheduler

* Migrate MqttHandleDtu to TaskScheduler

* Migrate MqttHandleInverter to TaskScheduler

* Migrate LedSingle to TaskScheduler

* Migrate NetworkSettings to TaskScheduler

* Migrate InverterSettings to TaskScheduler

* Migrate MessageOutput to TaskScheduler

* Migrate Display_Graphic to TaskScheduler

* Migrate WebApi to TaskScheduler

* Split InverterSettings into multiple tasks

* Calculate SunPosition only every 5 seconds

* Split LedSingle into multiple tasks

* Upgrade espMqttClient from 1.4.5 to 1.5.0

* Doc: Correct amount of MPP-Tracker

* Added HMT-1600-4T and HMT-1800-4T to DevInfoParser

Fix #1524

* Adjusted inverter names for HMS-1600/1800/2000-4T

* Add channel count to description of detected inverter type (DevInfoParser)

* Adjust device web api endpoint for dynamic led count

* Feature: Added ability to change the brightness of the LEDs

Based on the idea of @moritzlerch with several modifications like pwmTable and structure

* webapp: Update dependencies

* Update olikraus/U8g2 from 2.35.7 to 2.35.8

* Remove not required onWebsocketEvent

* Remove code nesting

* Introduce several const statements

* Remove not required AsyncEventSource

* Doc: Added byte specification to each command

* Feature: Added basic Grid Profile parser which shows the used profile and version

Other values are still outstanding.

* Optimize AlarmLogParser to save memory

* Add libfrozen to project to create constexpr maps

* Feature: First version of GridProfile Parser which shows all values contained in the profile.

* webapp: Update dependencies

* Apply better variable names

* Remove not required casts

* Add additional compiler flags to prevent errors

* Add const statement to several variables

* Replace NULL by nullptr

* Update bblanchon/ArduinoJson from 6.21.3 to 6.21.4

* Add const keyword to method parameters

* Add const keyword to methods

* Use references instead of pointers whenver possible

* Adjust member variable names in MqttSettings

* Adjust member variable names in NetworkSettings

* webapp: Update timezone database to latest version

* webapp: Beautify and unify form footers

* Feature: Allow setting of an inverter limit of 0% and 0W

Thanks to @madmartin in #1270

* Feature: Allow links in device profiles

These links will be shown on the hardware settings page.

* Doc: Added hint regarding HMS-xxxx-xT-NA inverters

* Feature: Added DeviceProfile for CASmo-DTU

Based on #1565

* Upgrade actions/upload-artifact from v3 to v4

* Upgrade actions/download-artifact from v3 to v4

* webapp: add app.js.gz

* Gridprofileparser: Added latest known values

Thanks to @stefan123t and @noone2k

* webapp: Fix lint errors

* Feature: Add DTU to Home Assistant Auto Discovery

This is based on PR 1365 from @CFenner with several fixes and optimizations

* Fix: Remove debug output as it floods the console

* Fix: Gridprofileparser: Add additional error handling if profile is unknown

* webapp: add app.js.gz

* Fix: Offset cache for "YieldDay" did not work correctly

* webapp: update dependencies

* webapp: add app.js.gz

* Fix: yarn.lock was outdated

* Fix: yarn build error

* Fix: Reset Yield day correction in combination with Zero Yield Day on Midnight lead to wrong values.

* Fix: Allow negative values in GridProfileParser

* Correct variable name

* Fix #1579: Static IP in Ethernet mode did not work correctly

* Feature: Added diagram to display

This is based on the idea of @Henrik-Ingenieur and was discussed in #1504

* webapp: update dependencies

* webapp: add app.js.gz

---------

Co-authored-by: Thomas Basler <thomas@familie-basler.net>
Co-authored-by: Pierre Kancir <pierre.kancir.emn@gmail.com>
2023-12-27 11:49:57 +01:00

141 lines
4.3 KiB
C++

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2023 Thomas Basler and others
*/
#include "HoymilesRadio.h"
#include "Hoymiles.h"
#include "crc.h"
serial_u HoymilesRadio::DtuSerial() const
{
return _dtuSerial;
}
void HoymilesRadio::setDtuSerial(const uint64_t serial)
{
_dtuSerial.u64 = serial;
}
serial_u HoymilesRadio::convertSerialToRadioId(const serial_u serial)
{
serial_u radioId;
radioId.u64 = 0;
radioId.b[4] = serial.b[0];
radioId.b[3] = serial.b[1];
radioId.b[2] = serial.b[2];
radioId.b[1] = serial.b[3];
radioId.b[0] = 0x01;
return radioId;
}
bool HoymilesRadio::checkFragmentCrc(const fragment_t& fragment) const
{
const uint8_t crc = crc8(fragment.fragment, fragment.len - 1);
return (crc == fragment.fragment[fragment.len - 1]);
}
void HoymilesRadio::sendRetransmitPacket(const uint8_t fragment_id)
{
CommandAbstract* cmd = _commandQueue.front().get();
CommandAbstract* requestCmd = cmd->getRequestFrameCommand(fragment_id);
if (requestCmd != nullptr) {
sendEsbPacket(*requestCmd);
}
}
void HoymilesRadio::sendLastPacketAgain()
{
CommandAbstract* cmd = _commandQueue.front().get();
sendEsbPacket(*cmd);
}
void HoymilesRadio::handleReceivedPackage()
{
if (_busyFlag && _rxTimeout.occured()) {
Hoymiles.getVerboseMessageOutput()->println("RX Period End");
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
if (nullptr != inv) {
CommandAbstract* cmd = _commandQueue.front().get();
uint8_t verifyResult = inv->verifyAllFragments(*cmd);
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
sendLastPacketAgain();
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
Hoymiles.getMessageOutput()->println("Retransmit timeout");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
Hoymiles.getMessageOutput()->println("Packet handling error");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult > 0) {
// Perform Retransmit
Hoymiles.getMessageOutput()->print("Request retransmit: ");
Hoymiles.getMessageOutput()->println(verifyResult);
sendRetransmitPacket(verifyResult);
} else {
// Successful received all packages
Hoymiles.getMessageOutput()->println("Success");
_commandQueue.pop();
_busyFlag = false;
}
} else {
// If inverter was not found, assume the command is invalid
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
_commandQueue.pop();
_busyFlag = false;
}
} else if (!_busyFlag) {
// Currently in idle mode --> send packet if one is in the queue
if (!isQueueEmpty()) {
CommandAbstract* cmd = _commandQueue.front().get();
auto inv = Hoymiles.getInverterBySerial(cmd->getTargetAddress());
if (nullptr != inv) {
inv->clearRxFragmentBuffer();
sendEsbPacket(*cmd);
} else {
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
_commandQueue.pop();
}
}
}
}
void HoymilesRadio::dumpBuf(const uint8_t buf[], const uint8_t len, const bool appendNewline)
{
for (uint8_t i = 0; i < len; i++) {
Hoymiles.getVerboseMessageOutput()->printf("%02X ", buf[i]);
}
if (appendNewline) {
Hoymiles.getVerboseMessageOutput()->println("");
}
}
bool HoymilesRadio::isInitialized() const
{
return _isInitialized;
}
bool HoymilesRadio::isIdle() const
{
return !_busyFlag;
}
bool HoymilesRadio::isQueueEmpty() const
{
return _commandQueue.size() == 0;
}