Merge branch 'development'
This commit is contained in:
commit
4324ae3081
@ -4,6 +4,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include <mcp_can.h>
|
#include <mcp_can.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#ifndef HUAWEI_PIN_MISO
|
#ifndef HUAWEI_PIN_MISO
|
||||||
#define HUAWEI_PIN_MISO 12
|
#define HUAWEI_PIN_MISO 12
|
||||||
@ -34,35 +35,45 @@
|
|||||||
|
|
||||||
#define MAX_CURRENT_MULTIPLIER 20
|
#define MAX_CURRENT_MULTIPLIER 20
|
||||||
|
|
||||||
|
// Index values for rec_values array
|
||||||
|
#define HUAWEI_INPUT_POWER_IDX 0
|
||||||
|
#define HUAWEI_INPUT_FREQ_IDX 1
|
||||||
|
#define HUAWEI_INPUT_CURRENT_IDX 2
|
||||||
|
#define HUAWEI_OUTPUT_POWER_IDX 3
|
||||||
|
#define HUAWEI_EFFICIENCY_IDX 4
|
||||||
|
#define HUAWEI_OUTPUT_VOLTAGE_IDX 5
|
||||||
|
#define HUAWEI_OUTPUT_CURRENT_MAX_IDX 6
|
||||||
|
#define HUAWEI_INPUT_VOLTAGE_IDX 7
|
||||||
|
#define HUAWEI_OUTPUT_TEMPERATURE_IDX 8
|
||||||
|
#define HUAWEI_INPUT_TEMPERATURE_IDX 9
|
||||||
|
#define HUAWEI_OUTPUT_CURRENT_IDX 10
|
||||||
|
#define HUAWEI_OUTPUT_CURRENT1_IDX 11
|
||||||
|
|
||||||
|
// Defines and index values for tx_values array
|
||||||
#define HUAWEI_OFFLINE_VOLTAGE 0x01
|
#define HUAWEI_OFFLINE_VOLTAGE 0x01
|
||||||
#define HUAWEI_ONLINE_VOLTAGE 0x00
|
#define HUAWEI_ONLINE_VOLTAGE 0x00
|
||||||
#define HUAWEI_OFFLINE_CURRENT 0x04
|
#define HUAWEI_OFFLINE_CURRENT 0x04
|
||||||
#define HUAWEI_ONLINE_CURRENT 0x03
|
#define HUAWEI_ONLINE_CURRENT 0x03
|
||||||
|
|
||||||
#define R48xx_DATA_INPUT_POWER 0x70
|
// Modes of operation
|
||||||
#define R48xx_DATA_INPUT_FREQ 0x71
|
|
||||||
#define R48xx_DATA_INPUT_CURRENT 0x72
|
|
||||||
#define R48xx_DATA_OUTPUT_POWER 0x73
|
|
||||||
#define R48xx_DATA_EFFICIENCY 0x74
|
|
||||||
#define R48xx_DATA_OUTPUT_VOLTAGE 0x75
|
|
||||||
#define R48xx_DATA_OUTPUT_CURRENT_MAX 0x76
|
|
||||||
#define R48xx_DATA_INPUT_VOLTAGE 0x78
|
|
||||||
#define R48xx_DATA_OUTPUT_TEMPERATURE 0x7F
|
|
||||||
#define R48xx_DATA_INPUT_TEMPERATURE 0x80
|
|
||||||
#define R48xx_DATA_OUTPUT_CURRENT 0x81
|
|
||||||
#define R48xx_DATA_OUTPUT_CURRENT1 0x82
|
|
||||||
|
|
||||||
#define HUAWEI_MODE_OFF 0
|
#define HUAWEI_MODE_OFF 0
|
||||||
#define HUAWEI_MODE_ON 1
|
#define HUAWEI_MODE_ON 1
|
||||||
#define HUAWEI_MODE_AUTO_EXT 2
|
#define HUAWEI_MODE_AUTO_EXT 2
|
||||||
#define HUAWEI_MODE_AUTO_INT 3
|
#define HUAWEI_MODE_AUTO_INT 3
|
||||||
|
|
||||||
|
// Error codes
|
||||||
|
#define HUAWEI_ERROR_CODE_RX 0x01
|
||||||
|
#define HUAWEI_ERROR_CODE_TX 0x02
|
||||||
|
|
||||||
// Wait time/current before shuting down the PSU / charger
|
// Wait time/current before shuting down the PSU / charger
|
||||||
// This is set to allow the fan to run for some time
|
// This is set to allow the fan to run for some time
|
||||||
#define HUAWEI_AUTO_MODE_SHUTDOWN_DELAY 60000
|
#define HUAWEI_AUTO_MODE_SHUTDOWN_DELAY 60000
|
||||||
#define HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT 1.0
|
#define HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT 1.0
|
||||||
|
|
||||||
struct RectifierParameters_t {
|
// Updateinterval used to request new values from the PSU
|
||||||
|
#define HUAWEI_DATA_REQUEST_INTERVAL_MS 2500
|
||||||
|
|
||||||
|
typedef struct RectifierParameters {
|
||||||
float input_voltage;
|
float input_voltage;
|
||||||
float input_frequency;
|
float input_frequency;
|
||||||
float input_current;
|
float input_current;
|
||||||
@ -75,6 +86,33 @@ struct RectifierParameters_t {
|
|||||||
float output_power;
|
float output_power;
|
||||||
float output_temp;
|
float output_temp;
|
||||||
float amp_hour;
|
float amp_hour;
|
||||||
|
} RectifierParameters_t;
|
||||||
|
|
||||||
|
class HuaweiCanCommClass {
|
||||||
|
public:
|
||||||
|
bool init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs);
|
||||||
|
void loop();
|
||||||
|
bool gotNewRxDataFrame(bool clear);
|
||||||
|
uint8_t getErrorCode(bool clear);
|
||||||
|
uint32_t getParameterValue(uint8_t parameter);
|
||||||
|
void setParameterValue(uint16_t in, uint8_t parameterType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendRequest();
|
||||||
|
|
||||||
|
SPIClass *SPI;
|
||||||
|
MCP_CAN *_CAN;
|
||||||
|
uint8_t _huaweiIrq; // IRQ pin
|
||||||
|
uint32_t _nextRequestMillis = 0; // When to send next data request to PSU
|
||||||
|
|
||||||
|
std::mutex _mutex;
|
||||||
|
|
||||||
|
uint32_t _recValues[12];
|
||||||
|
uint16_t _txValues[5];
|
||||||
|
bool _hasNewTxValue[5];
|
||||||
|
|
||||||
|
uint8_t _errorCode;
|
||||||
|
bool _completeUpdateReceived;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HuaweiCanClass {
|
class HuaweiCanClass {
|
||||||
@ -89,26 +127,24 @@ public:
|
|||||||
bool getAutoPowerStatus();
|
bool getAutoPowerStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendRequest();
|
void processReceivedParameters();
|
||||||
void onReceive(uint8_t* frame, uint8_t len);
|
|
||||||
|
|
||||||
SPIClass *spi;
|
TaskHandle_t _HuaweiCanCommunicationTaskHdl = NULL;
|
||||||
MCP_CAN *CAN;
|
|
||||||
bool _initialized = false;
|
bool _initialized = false;
|
||||||
uint8_t _huawei_irq; // IRQ pin
|
uint8_t _huaweiPower; // Power pin
|
||||||
uint8_t _huawei_power; // Power pin
|
|
||||||
uint8_t _mode = HUAWEI_MODE_AUTO_EXT;
|
uint8_t _mode = HUAWEI_MODE_AUTO_EXT;
|
||||||
|
|
||||||
RectifierParameters_t _rp;
|
RectifierParameters_t _rp;
|
||||||
|
|
||||||
uint32_t _lastUpdateReceivedMillis; // Timestamp for last data seen from the PSU
|
uint32_t _lastUpdateReceivedMillis; // Timestamp for last data seen from the PSU
|
||||||
uint32_t _nextRequestMillis = 0; // When to send next data request to PSU
|
|
||||||
uint32_t _nextAutoModePeriodicIntMillis; // When to send the next output volume request in Automatic mode
|
|
||||||
uint32_t _lastPowerMeterUpdateReceivedMillis; // Timestamp of last power meter value
|
|
||||||
uint32_t _outputCurrentOnSinceMillis; // Timestamp since when the PSU was idle at zero amps
|
uint32_t _outputCurrentOnSinceMillis; // Timestamp since when the PSU was idle at zero amps
|
||||||
bool _newOutputPowerReceived = false;
|
uint32_t _nextAutoModePeriodicIntMillis; // When to set the next output voltage in automatic mode
|
||||||
uint8_t _autoPowerEnabled = false;
|
uint32_t _lastPowerMeterUpdateReceivedMillis; // Timestamp of last seen power meter value
|
||||||
bool _autoPowerActive = false;
|
uint32_t _autoModeBlockedTillMillis = 0; // Timestamp to block running auto mode for some time
|
||||||
|
|
||||||
|
uint8_t _autoPowerEnabledCounter = 0;
|
||||||
|
bool _autoPowerEnabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern HuaweiCanClass HuaweiCan;
|
extern HuaweiCanClass HuaweiCan;
|
||||||
|
extern HuaweiCanCommClass HuaweiCanComm;
|
||||||
@ -10,9 +10,181 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <mcp_can.h>
|
#include <mcp_can.h>
|
||||||
|
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
HuaweiCanClass HuaweiCan;
|
HuaweiCanClass HuaweiCan;
|
||||||
|
HuaweiCanCommClass HuaweiCanComm;
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// Huawei CAN Communication
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
// Using a C function to avoid static C++ member
|
||||||
|
void HuaweiCanCommunicationTask(void* parameter) {
|
||||||
|
for( ;; ) {
|
||||||
|
HuaweiCanComm.loop();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HuaweiCanCommClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs) {
|
||||||
|
SPI = new SPIClass(HSPI);
|
||||||
|
SPI->begin(huawei_clk, huawei_miso, huawei_mosi, huawei_cs);
|
||||||
|
pinMode(huawei_cs, OUTPUT);
|
||||||
|
digitalWrite(huawei_cs, HIGH);
|
||||||
|
|
||||||
|
pinMode(huawei_irq, INPUT_PULLUP);
|
||||||
|
_huaweiIrq = huawei_irq;
|
||||||
|
|
||||||
|
_CAN = new MCP_CAN(SPI, huawei_cs);
|
||||||
|
if (!_CAN->begin(MCP_STDEXT, CAN_125KBPS, MCP_8MHZ) == CAN_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t myMask = 0xFFFFFFFF; // Look at all incoming bits and...
|
||||||
|
const uint32_t myFilter = 0x1081407F; // filter for this message only
|
||||||
|
_CAN->init_Mask(0, 1, myMask);
|
||||||
|
_CAN->init_Filt(0, 1, myFilter);
|
||||||
|
_CAN->init_Mask(1, 1, myMask);
|
||||||
|
|
||||||
|
// Change to normal mode to allow messages to be transmitted
|
||||||
|
_CAN->setMode(MCP_NORMAL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public methods need to obtain semaphore
|
||||||
|
|
||||||
|
void HuaweiCanCommClass::loop()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
|
||||||
|
INT32U rxId;
|
||||||
|
unsigned char len = 0;
|
||||||
|
unsigned char rxBuf[8];
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
if (!digitalRead(_huaweiIrq)) {
|
||||||
|
// If CAN_INT pin is low, read receive buffer
|
||||||
|
_CAN->readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
|
||||||
|
if((rxId & 0x80000000) == 0x80000000) { // Determine if ID is standard (11 bits) or extended (29 bits)
|
||||||
|
if ((rxId & 0x1FFFFFFF) == 0x1081407F && len == 8) {
|
||||||
|
|
||||||
|
uint32_t value = __bswap32(* reinterpret_cast<uint32_t*> (rxBuf + 4));
|
||||||
|
|
||||||
|
// Input power 0x70, Input frequency 0x71, Input current 0x72
|
||||||
|
// Output power 0x73, Efficiency 0x74, Output Voltage 0x75 and Output Current 0x76
|
||||||
|
if(rxBuf[1] >= 0x70 && rxBuf[1] <= 0x76 ) {
|
||||||
|
_recValues[rxBuf[1] - 0x70] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input voltage
|
||||||
|
if(rxBuf[1] == 0x78 ) {
|
||||||
|
_recValues[HUAWEI_INPUT_VOLTAGE_IDX] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Temperature
|
||||||
|
if(rxBuf[1] == 0x7F ) {
|
||||||
|
_recValues[HUAWEI_OUTPUT_TEMPERATURE_IDX] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input Temperature 0x80, Output Current 1 0x81 and Output Current 2 0x82
|
||||||
|
if(rxBuf[1] >= 0x80 && rxBuf[1] <= 0x82 ) {
|
||||||
|
_recValues[rxBuf[1] - 0x80 + HUAWEI_INPUT_TEMPERATURE_IDX] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the last value that is send
|
||||||
|
if(rxBuf[1] == 0x81) {
|
||||||
|
_completeUpdateReceived = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Other emitted codes not handled here are: 0x1081407E (Ack), 0x1081807E (Ack Frame), 0x1081D27F (Description), 0x1001117E (Whr meter), 0x100011FE (unclear), 0x108111FE (output enabled), 0x108081FE (unclear). See:
|
||||||
|
// https://github.com/craigpeacock/Huawei_R4850G2_CAN/blob/main/r4850.c
|
||||||
|
// https://www.beyondlogic.org/review-huawei-r4850g2-power-supply-53-5vdc-3kw/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit values
|
||||||
|
for (i = 0; i < HUAWEI_OFFLINE_CURRENT; i++) {
|
||||||
|
if ( _hasNewTxValue[i] == true) {
|
||||||
|
uint8_t data[8] = {0x01, i, 0x00, 0x00, 0x00, 0x00, (uint8_t)((_txValues[i] & 0xFF00) >> 8), (uint8_t)(_txValues[i] & 0xFF)};
|
||||||
|
|
||||||
|
// Send extended message
|
||||||
|
byte sndStat = _CAN->sendMsgBuf(0x108180FE, 1, 8, data);
|
||||||
|
if (sndStat == CAN_OK) {
|
||||||
|
_hasNewTxValue[i] = false;
|
||||||
|
} else {
|
||||||
|
_errorCode |= HUAWEI_ERROR_CODE_TX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_nextRequestMillis < millis()) {
|
||||||
|
sendRequest();
|
||||||
|
_nextRequestMillis = millis() + HUAWEI_DATA_REQUEST_INTERVAL_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t HuaweiCanCommClass::getParameterValue(uint8_t parameter)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
uint32_t v = 0;
|
||||||
|
if (parameter < HUAWEI_OUTPUT_CURRENT1_IDX) {
|
||||||
|
v = _recValues[parameter];
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HuaweiCanCommClass::gotNewRxDataFrame(bool clear)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
bool b = false;
|
||||||
|
b = _completeUpdateReceived;
|
||||||
|
if (clear) {
|
||||||
|
_completeUpdateReceived = false;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HuaweiCanCommClass::getErrorCode(bool clear)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
uint8_t e = 0;
|
||||||
|
e = _errorCode;
|
||||||
|
if (clear) {
|
||||||
|
_errorCode = 0;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HuaweiCanCommClass::setParameterValue(uint16_t in, uint8_t parameterType)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
if (parameterType < HUAWEI_OFFLINE_CURRENT) {
|
||||||
|
_txValues[parameterType] = in;
|
||||||
|
_hasNewTxValue[parameterType] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods
|
||||||
|
// Requests current values from Huawei unit. Response is handled in onReceive
|
||||||
|
void HuaweiCanCommClass::sendRequest()
|
||||||
|
{
|
||||||
|
uint8_t data[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
//Send extended message
|
||||||
|
byte sndStat = _CAN->sendMsgBuf(0x108040FE, 1, 8, data);
|
||||||
|
if(sndStat != CAN_OK) {
|
||||||
|
_errorCode |= HUAWEI_ERROR_CODE_RX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// Huawei CAN Controller
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power)
|
void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power)
|
||||||
{
|
{
|
||||||
@ -26,33 +198,23 @@ void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huaw
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi = new SPIClass(HSPI);
|
if (!HuaweiCanComm.init(huawei_miso, huawei_mosi, huawei_clk, huawei_irq, huawei_cs)) {
|
||||||
spi->begin(huawei_clk, huawei_miso, huawei_mosi, huawei_cs);
|
MessageOutput.println("[HuaweiCanClass::init] Error Initializing Huawei CAN communication...");
|
||||||
pinMode(huawei_cs, OUTPUT);
|
|
||||||
digitalWrite(huawei_cs, HIGH);
|
|
||||||
|
|
||||||
pinMode(huawei_irq, INPUT_PULLUP);
|
|
||||||
_huawei_irq = huawei_irq;
|
|
||||||
|
|
||||||
CAN = new MCP_CAN(spi, huawei_cs);
|
|
||||||
if (!CAN->begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK) {
|
|
||||||
MessageOutput.println("[HuaweiCanClass::init] Error Initializing MCP2515...");
|
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
MessageOutput.println("[HuaweiCanClass::init] MCP2515 Initialized Successfully!");
|
|
||||||
_initialized = true;
|
|
||||||
|
|
||||||
// Change to normal mode to allow messages to be transmitted
|
|
||||||
CAN->setMode(MCP_NORMAL);
|
|
||||||
|
|
||||||
pinMode(huawei_power, OUTPUT);
|
pinMode(huawei_power, OUTPUT);
|
||||||
digitalWrite(huawei_power, HIGH);
|
digitalWrite(huawei_power, HIGH);
|
||||||
_huawei_power = huawei_power;
|
_huaweiPower = huawei_power;
|
||||||
|
|
||||||
if (config.Huawei_Auto_Power_Enabled) {
|
if (config.Huawei_Auto_Power_Enabled) {
|
||||||
_mode = HUAWEI_MODE_AUTO_INT;
|
_mode = HUAWEI_MODE_AUTO_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xTaskCreate(HuaweiCanCommunicationTask,"HUAWEI_CAN_0",1000,NULL,0,&_HuaweiCanCommunicationTaskHdl);
|
||||||
|
|
||||||
|
MessageOutput.println("[HuaweiCanClass::init] MCP2515 Initialized Successfully!");
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RectifierParameters_t * HuaweiCanClass::get()
|
RectifierParameters_t * HuaweiCanClass::get()
|
||||||
@ -65,136 +227,58 @@ uint32_t HuaweiCanClass::getLastUpdate()
|
|||||||
return _lastUpdateReceivedMillis;
|
return _lastUpdateReceivedMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
void HuaweiCanClass::processReceivedParameters()
|
||||||
|
|
||||||
// Requests current values from Huawei unit. Response is handled in onReceive
|
|
||||||
void HuaweiCanClass::sendRequest()
|
|
||||||
{
|
{
|
||||||
// Send extended message
|
_rp.input_power = HuaweiCanComm.getParameterValue(HUAWEI_INPUT_POWER_IDX) / 1024.0;
|
||||||
byte sndStat = CAN->sendMsgBuf(0x108040FE, 1, 8, data);
|
_rp.input_frequency = HuaweiCanComm.getParameterValue(HUAWEI_INPUT_FREQ_IDX) / 1024.0;
|
||||||
if(sndStat != CAN_OK) {
|
_rp.input_current = HuaweiCanComm.getParameterValue(HUAWEI_INPUT_CURRENT_IDX) / 1024.0;
|
||||||
MessageOutput.println("[HuaweiCanClass::sendRequest] Error Sending Message...");
|
_rp.output_power = HuaweiCanComm.getParameterValue(HUAWEI_OUTPUT_POWER_IDX) / 1024.0;
|
||||||
}
|
_rp.efficiency = HuaweiCanComm.getParameterValue(HUAWEI_EFFICIENCY_IDX) / 1024.0;
|
||||||
}
|
_rp.output_voltage = HuaweiCanComm.getParameterValue(HUAWEI_OUTPUT_VOLTAGE_IDX) / 1024.0;
|
||||||
|
_rp.max_output_current = static_cast<float>(HuaweiCanComm.getParameterValue(HUAWEI_OUTPUT_CURRENT_MAX_IDX)) / MAX_CURRENT_MULTIPLIER;
|
||||||
|
_rp.input_voltage = HuaweiCanComm.getParameterValue(HUAWEI_INPUT_VOLTAGE_IDX) / 1024.0;
|
||||||
|
_rp.output_temp = HuaweiCanComm.getParameterValue(HUAWEI_OUTPUT_TEMPERATURE_IDX) / 1024.0;
|
||||||
|
_rp.input_temp = HuaweiCanComm.getParameterValue(HUAWEI_INPUT_TEMPERATURE_IDX) / 1024.0;
|
||||||
|
_rp.output_current = HuaweiCanComm.getParameterValue(HUAWEI_OUTPUT_CURRENT_IDX) / 1024.0;
|
||||||
|
|
||||||
void HuaweiCanClass::onReceive(uint8_t* frame, uint8_t len)
|
if (HuaweiCanComm.gotNewRxDataFrame(true)) {
|
||||||
{
|
|
||||||
if (len != 8) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t value = __bswap32(* reinterpret_cast<uint32_t*> (frame + 4));
|
|
||||||
|
|
||||||
switch (frame[1]) {
|
|
||||||
case R48xx_DATA_INPUT_POWER:
|
|
||||||
_rp.input_power = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_INPUT_FREQ:
|
|
||||||
_rp.input_frequency = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_INPUT_CURRENT:
|
|
||||||
_rp.input_current = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_POWER:
|
|
||||||
_rp.output_power = value / 1024.0;
|
|
||||||
_newOutputPowerReceived = true;
|
|
||||||
// We'll only update last update on the important params
|
|
||||||
_lastUpdateReceivedMillis = millis();
|
_lastUpdateReceivedMillis = millis();
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_EFFICIENCY:
|
|
||||||
_rp.efficiency = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_VOLTAGE:
|
|
||||||
_rp.output_voltage = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_CURRENT_MAX:
|
|
||||||
_rp.max_output_current = static_cast<float>(value) / MAX_CURRENT_MULTIPLIER;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_INPUT_VOLTAGE:
|
|
||||||
_rp.input_voltage = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_TEMPERATURE:
|
|
||||||
_rp.output_temp = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_INPUT_TEMPERATURE:
|
|
||||||
_rp.input_temp = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_CURRENT1:
|
|
||||||
// printf("Output Current(1) %.02fA\r\n", value / 1024.0);
|
|
||||||
// output_current = value / 1024.0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R48xx_DATA_OUTPUT_CURRENT:
|
|
||||||
_rp.output_current = value / 1024.0;
|
|
||||||
|
|
||||||
if (_rp.output_current > HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT) {
|
|
||||||
_outputCurrentOnSinceMillis = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is normally the last parameter received. Print */
|
|
||||||
_lastUpdateReceivedMillis = millis(); // We'll only update last update on the important params
|
|
||||||
|
|
||||||
MessageOutput.printf("[HuaweiCanClass::onReceive] In: %.02fV, %.02fA, %.02fW\n", _rp.input_voltage, _rp.input_current, _rp.input_power);
|
|
||||||
MessageOutput.printf("[HuaweiCanClass::onReceive] Out: %.02fV, %.02fA of %.02fA, %.02fW\n", _rp.output_voltage, _rp.output_current, _rp.max_output_current, _rp.output_power);
|
|
||||||
MessageOutput.printf("[HuaweiCanClass::onReceive] Eff: %.01f%%, Temp in: %.01fC, Temp out: %.01fC\n", _rp.efficiency * 100, _rp.input_temp, _rp.output_temp);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// printf("Unknown parameter 0x%02X, 0x%04X\r\n",frame[1], value);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HuaweiCanClass::loop()
|
void HuaweiCanClass::loop()
|
||||||
{
|
{
|
||||||
|
|
||||||
INT32U rxId;
|
|
||||||
unsigned char len = 0;
|
|
||||||
unsigned char rxBuf[8];
|
|
||||||
|
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
if (!config.Huawei_Enabled || !_initialized) {
|
if (!config.Huawei_Enabled || !_initialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!digitalRead(_huawei_irq)) {
|
processReceivedParameters();
|
||||||
// If CAN_INT pin is low, read receive buffer
|
|
||||||
CAN->readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
|
|
||||||
|
|
||||||
if((rxId & 0x80000000) == 0x80000000) { // Determine if ID is standard (11 bits) or extended (29 bits)
|
uint8_t com_error = HuaweiCanComm.getErrorCode(true);
|
||||||
// MessageOutput.printf("Extended ID: 0x%.8lX DLC: %1d \n", (rxId & 0x1FFFFFFF), len);
|
if (com_error && HUAWEI_ERROR_CODE_RX) {
|
||||||
if ((rxId & 0x1FFFFFFF) == 0x1081407F) {
|
MessageOutput.println("[HuaweiCanClass::loop] Data request error");
|
||||||
onReceive(rxBuf, len);
|
|
||||||
}
|
|
||||||
// Other emitted codes not handled here are: 0x1081407E, 0x1081807E, 0x1081D27F, 0x1001117E, 0x100011FE, 0x108111FE, 0x108081FE. See:
|
|
||||||
// https://github.com/craigpeacock/Huawei_R4850G2_CAN/blob/main/r4850.c
|
|
||||||
// https://www.beyondlogic.org/review-huawei-r4850g2-power-supply-53-5vdc-3kw/
|
|
||||||
}
|
}
|
||||||
|
if (com_error && HUAWEI_ERROR_CODE_TX) {
|
||||||
|
MessageOutput.println("[HuaweiCanClass::loop] Data set error");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request updated values in regular intervals
|
// Print updated data
|
||||||
if (_nextRequestMillis < millis()) {
|
if (HuaweiCanComm.gotNewRxDataFrame(false)) {
|
||||||
MessageOutput.println("[HUAWEI********************* Sending request");
|
MessageOutput.printf("[HuaweiCanClass::loop] In: %.02fV, %.02fA, %.02fW\n", _rp.input_voltage, _rp.input_current, _rp.input_power);
|
||||||
sendRequest();
|
MessageOutput.printf("[HuaweiCanClass::loop] Out: %.02fV, %.02fA of %.02fA, %.02fW\n", _rp.output_voltage, _rp.output_current, _rp.max_output_current, _rp.output_power);
|
||||||
_nextRequestMillis = millis() + 5000;
|
MessageOutput.printf("[HuaweiCanClass::loop] Eff : %.01f%%, Temp in: %.01fC, Temp out: %.01fC\n", _rp.efficiency * 100, _rp.input_temp, _rp.output_temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the output current is low for a long time, shutdown PSU
|
// Internal PSU power pin (slot detect) control
|
||||||
|
if (_rp.output_current > HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT) {
|
||||||
|
_outputCurrentOnSinceMillis = millis();
|
||||||
|
}
|
||||||
if (_outputCurrentOnSinceMillis + HUAWEI_AUTO_MODE_SHUTDOWN_DELAY < millis() &&
|
if (_outputCurrentOnSinceMillis + HUAWEI_AUTO_MODE_SHUTDOWN_DELAY < millis() &&
|
||||||
(_mode == HUAWEI_MODE_AUTO_EXT || _mode == HUAWEI_MODE_AUTO_INT)) {
|
(_mode == HUAWEI_MODE_AUTO_EXT || _mode == HUAWEI_MODE_AUTO_INT)) {
|
||||||
digitalWrite(_huawei_power, 1);
|
digitalWrite(_huaweiPower, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***********************
|
// ***********************
|
||||||
@ -210,21 +294,37 @@ void HuaweiCanClass::loop()
|
|||||||
_nextAutoModePeriodicIntMillis = millis() + 60000;
|
_nextAutoModePeriodicIntMillis = millis() + 60000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-enable automatic power control if the output voltage has dropped below threshold
|
// Check if we should run automatic power calculation at all.
|
||||||
if(_rp.output_voltage < config.Huawei_Auto_Power_Enable_Voltage_Limit ) {
|
// We may have set a value recently and still wait for output stabilization
|
||||||
_autoPowerEnabled = 10;
|
if (_autoModeBlockedTillMillis > millis()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((PowerLimiter.getPowerLimiterState() == PL_UI_STATE_INACTIVE ||
|
// Re-enable automatic power control if the output voltage has dropped below threshold
|
||||||
PowerLimiter.getPowerLimiterState() == PL_UI_STATE_CHARGING) &&
|
if(_rp.output_voltage < config.Huawei_Auto_Power_Enable_Voltage_Limit ) {
|
||||||
PowerMeter.getLastPowerMeterUpdate() > _lastPowerMeterUpdateReceivedMillis &&
|
_autoPowerEnabledCounter = 10;
|
||||||
_newOutputPowerReceived &&
|
}
|
||||||
_autoPowerEnabled > 0) {
|
|
||||||
// Power Limiter is inactive and we have received both:
|
|
||||||
// a new PowerMeter and a new output power value. Also we're _autoPowerEnabled
|
// Check if inverter used by the power limiter is active
|
||||||
|
std::shared_ptr<InverterAbstract> inverter =
|
||||||
|
Hoymiles.getInverterByPos(config.PowerLimiter_InverterId);
|
||||||
|
|
||||||
|
if (inverter != nullptr) {
|
||||||
|
if(inverter->isProducing()) {
|
||||||
|
setValue(0.0, HUAWEI_ONLINE_CURRENT);
|
||||||
|
// Don't run auto mode for a second now. Otherwise we may send too much over the CAN bus
|
||||||
|
_autoModeBlockedTillMillis = millis() + 1000;
|
||||||
|
MessageOutput.printf("[HuaweiCanClass::loop] Inverter is active, disable\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PowerMeter.getLastPowerMeterUpdate() > _lastPowerMeterUpdateReceivedMillis &&
|
||||||
|
_autoPowerEnabledCounter > 0) {
|
||||||
|
// We have received a new PowerMeter value. Also we're _autoPowerEnabled
|
||||||
// So we're good to calculate a new limit
|
// So we're good to calculate a new limit
|
||||||
|
|
||||||
_newOutputPowerReceived = false;
|
|
||||||
_lastPowerMeterUpdateReceivedMillis = PowerMeter.getLastPowerMeterUpdate();
|
_lastPowerMeterUpdateReceivedMillis = PowerMeter.getLastPowerMeterUpdate();
|
||||||
|
|
||||||
// Calculate new power limit
|
// Calculate new power limit
|
||||||
@ -239,14 +339,14 @@ void HuaweiCanClass::loop()
|
|||||||
// to ramp up from zero output power when starting up
|
// to ramp up from zero output power when starting up
|
||||||
if (_rp.output_power < config.Huawei_Auto_Power_Lower_Power_Limit) {
|
if (_rp.output_power < config.Huawei_Auto_Power_Lower_Power_Limit) {
|
||||||
MessageOutput.printf("[HuaweiCanClass::loop] Power and voltage limit reached. Disabling automatic power control .... \r\n");
|
MessageOutput.printf("[HuaweiCanClass::loop] Power and voltage limit reached. Disabling automatic power control .... \r\n");
|
||||||
_autoPowerEnabled--;
|
_autoPowerEnabledCounter--;
|
||||||
if (_autoPowerEnabled == 0) {
|
if (_autoPowerEnabledCounter == 0) {
|
||||||
_autoPowerActive = false;
|
_autoPowerEnabled = false;
|
||||||
setValue(0, HUAWEI_ONLINE_CURRENT);
|
setValue(0, HUAWEI_ONLINE_CURRENT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_autoPowerEnabled = 10;
|
_autoPowerEnabledCounter = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit power to maximum
|
// Limit power to maximum
|
||||||
@ -258,14 +358,14 @@ void HuaweiCanClass::loop()
|
|||||||
float efficiency = (_rp.efficiency > 0.5 ? _rp.efficiency : 1.0);
|
float efficiency = (_rp.efficiency > 0.5 ? _rp.efficiency : 1.0);
|
||||||
float outputCurrent = efficiency * (newPowerLimit / _rp.output_voltage);
|
float outputCurrent = efficiency * (newPowerLimit / _rp.output_voltage);
|
||||||
MessageOutput.printf("[HuaweiCanClass::loop] Output current %f \r\n", outputCurrent);
|
MessageOutput.printf("[HuaweiCanClass::loop] Output current %f \r\n", outputCurrent);
|
||||||
_autoPowerActive = true;
|
_autoPowerEnabled = true;
|
||||||
setValue(outputCurrent, HUAWEI_ONLINE_CURRENT);
|
setValue(outputCurrent, HUAWEI_ONLINE_CURRENT);
|
||||||
|
|
||||||
// Issue next request for updated output values in 2s to allow for output stabilization
|
// Don't run auto mode some time to allow for output stabilization after issuing a new value
|
||||||
_nextRequestMillis = millis() + 2000;
|
_autoModeBlockedTillMillis = millis() + 2 * HUAWEI_DATA_REQUEST_INTERVAL_MS;
|
||||||
} else {
|
} else {
|
||||||
// requested PL is below minium. Set current to 0
|
// requested PL is below minium. Set current to 0
|
||||||
_autoPowerActive = false;
|
_autoPowerEnabled = false;
|
||||||
setValue(0.0, HUAWEI_ONLINE_CURRENT);
|
setValue(0.0, HUAWEI_ONLINE_CURRENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,6 +374,13 @@ void HuaweiCanClass::loop()
|
|||||||
|
|
||||||
void HuaweiCanClass::setValue(float in, uint8_t parameterType)
|
void HuaweiCanClass::setValue(float in, uint8_t parameterType)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
|
if (!config.Huawei_Enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
|
|
||||||
if (in < 0) {
|
if (in < 0) {
|
||||||
@ -283,7 +390,7 @@ void HuaweiCanClass::setValue(float in, uint8_t parameterType)
|
|||||||
// Start PSU if needed
|
// Start PSU if needed
|
||||||
if (in > HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT && parameterType == HUAWEI_ONLINE_CURRENT &&
|
if (in > HUAWEI_AUTO_MODE_SHUTDOWN_CURRENT && parameterType == HUAWEI_ONLINE_CURRENT &&
|
||||||
(_mode == HUAWEI_MODE_AUTO_EXT || _mode == HUAWEI_MODE_AUTO_INT)) {
|
(_mode == HUAWEI_MODE_AUTO_EXT || _mode == HUAWEI_MODE_AUTO_INT)) {
|
||||||
digitalWrite(_huawei_power, 0);
|
digitalWrite(_huaweiPower, 0);
|
||||||
_outputCurrentOnSinceMillis = millis();
|
_outputCurrentOnSinceMillis = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,24 +402,22 @@ void HuaweiCanClass::setValue(float in, uint8_t parameterType)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[8] = {0x01, parameterType, 0x00, 0x00, 0x00, 0x00, (uint8_t)((value & 0xFF00) >> 8), (uint8_t)(value & 0xFF)};
|
HuaweiCanComm.setParameterValue(value, parameterType);
|
||||||
|
|
||||||
// Send extended message
|
|
||||||
byte sndStat = CAN->sendMsgBuf(0x108180FE, 1, 8, data);
|
|
||||||
if (sndStat != CAN_OK) {
|
|
||||||
MessageOutput.println("[HuaweiCanClass::setValue] Error Sending Message...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HuaweiCanClass::setMode(uint8_t mode) {
|
void HuaweiCanClass::setMode(uint8_t mode) {
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
|
if (!config.Huawei_Enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(mode == HUAWEI_MODE_OFF) {
|
if(mode == HUAWEI_MODE_OFF) {
|
||||||
digitalWrite(_huawei_power, 1);
|
digitalWrite(_huaweiPower, 1);
|
||||||
_mode = HUAWEI_MODE_OFF;
|
_mode = HUAWEI_MODE_OFF;
|
||||||
}
|
}
|
||||||
if(mode == HUAWEI_MODE_ON) {
|
if(mode == HUAWEI_MODE_ON) {
|
||||||
digitalWrite(_huawei_power, 0);
|
digitalWrite(_huaweiPower, 0);
|
||||||
_mode = HUAWEI_MODE_ON;
|
_mode = HUAWEI_MODE_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +427,7 @@ void HuaweiCanClass::setMode(uint8_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_mode == HUAWEI_MODE_AUTO_INT && mode != HUAWEI_MODE_AUTO_INT) {
|
if (_mode == HUAWEI_MODE_AUTO_INT && mode != HUAWEI_MODE_AUTO_INT) {
|
||||||
_autoPowerActive = false;
|
_autoPowerEnabled = false;
|
||||||
setValue(0, HUAWEI_ONLINE_CURRENT);
|
setValue(0, HUAWEI_ONLINE_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,6 +437,6 @@ void HuaweiCanClass::setMode(uint8_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HuaweiCanClass::getAutoPowerStatus() {
|
bool HuaweiCanClass::getAutoPowerStatus() {
|
||||||
return _autoPowerActive;
|
return _autoPowerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -83,14 +83,26 @@ void MqttHandleVedirectClass::loop()
|
|||||||
value = VeDirectMppt.veFrame.I;
|
value = VeDirectMppt.veFrame.I;
|
||||||
MqttSettings.publish(topic + "I", value);
|
MqttSettings.publish(topic + "I", value);
|
||||||
}
|
}
|
||||||
|
if (_PublishFull || VeDirectMppt.veFrame.P != _kvFrame.P) {
|
||||||
|
value = VeDirectMppt.veFrame.P;
|
||||||
|
MqttSettings.publish(topic + "P", value);
|
||||||
|
}
|
||||||
if (_PublishFull || VeDirectMppt.veFrame.VPV != _kvFrame.VPV) {
|
if (_PublishFull || VeDirectMppt.veFrame.VPV != _kvFrame.VPV) {
|
||||||
value = VeDirectMppt.veFrame.VPV;
|
value = VeDirectMppt.veFrame.VPV;
|
||||||
MqttSettings.publish(topic + "VPV", value);
|
MqttSettings.publish(topic + "VPV", value);
|
||||||
}
|
}
|
||||||
|
if (_PublishFull || VeDirectMppt.veFrame.IPV != _kvFrame.IPV) {
|
||||||
|
value = VeDirectMppt.veFrame.IPV;
|
||||||
|
MqttSettings.publish(topic + "IPV", value);
|
||||||
|
}
|
||||||
if (_PublishFull || VeDirectMppt.veFrame.PPV != _kvFrame.PPV) {
|
if (_PublishFull || VeDirectMppt.veFrame.PPV != _kvFrame.PPV) {
|
||||||
value = VeDirectMppt.veFrame.PPV;
|
value = VeDirectMppt.veFrame.PPV;
|
||||||
MqttSettings.publish(topic + "PPV", value);
|
MqttSettings.publish(topic + "PPV", value);
|
||||||
}
|
}
|
||||||
|
if (_PublishFull || VeDirectMppt.veFrame.E != _kvFrame.E) {
|
||||||
|
value = VeDirectMppt.veFrame.E;
|
||||||
|
MqttSettings.publish(topic + "E", value);
|
||||||
|
}
|
||||||
if (_PublishFull || VeDirectMppt.veFrame.H19 != _kvFrame.H19) {
|
if (_PublishFull || VeDirectMppt.veFrame.H19 != _kvFrame.H19) {
|
||||||
value = VeDirectMppt.veFrame.H19;
|
value = VeDirectMppt.veFrame.H19;
|
||||||
MqttSettings.publish(topic + "H19", value);
|
MqttSettings.publish(topic + "H19", value);
|
||||||
|
|||||||
@ -343,7 +343,7 @@ int32_t PowerLimiterClass::inverterPowerDcToAc(std::shared_ptr<InverterAbstract>
|
|||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
float inverterEfficiencyPercent = inverter->Statistics()->getChannelFieldValue(
|
float inverterEfficiencyPercent = inverter->Statistics()->getChannelFieldValue(
|
||||||
TYPE_AC, static_cast<ChannelNum_t>(config.PowerLimiter_InverterChannelId), FLD_EFF);
|
TYPE_AC, CH0, FLD_EFF);
|
||||||
|
|
||||||
// fall back to hoymiles peak efficiency as per datasheet if inverter
|
// fall back to hoymiles peak efficiency as per datasheet if inverter
|
||||||
// is currently not producing (efficiency is zero in that case)
|
// is currently not producing (efficiency is zero in that case)
|
||||||
@ -440,7 +440,7 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
|
|||||||
// the produced power of this inverter has also to be taken into account.
|
// the produced power of this inverter has also to be taken into account.
|
||||||
// We don't use FLD_PAC from the statistics, because that
|
// We don't use FLD_PAC from the statistics, because that
|
||||||
// data might be too old and unreliable.
|
// data might be too old and unreliable.
|
||||||
acPower = static_cast<int>(inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_PAC));
|
acPower = static_cast<int>(inverter->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PAC));
|
||||||
newPowerLimit += acPower;
|
newPowerLimit += acPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,7 +583,7 @@ float PowerLimiterClass::getLoadCorrectedVoltage()
|
|||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
auto channel = static_cast<ChannelNum_t>(config.PowerLimiter_InverterChannelId);
|
auto channel = static_cast<ChannelNum_t>(config.PowerLimiter_InverterChannelId);
|
||||||
float acPower = _inverter->Statistics()->getChannelFieldValue(TYPE_AC, channel, FLD_PAC);
|
float acPower = _inverter->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PAC);
|
||||||
float dcVoltage = _inverter->Statistics()->getChannelFieldValue(TYPE_DC, channel, FLD_UDC);
|
float dcVoltage = _inverter->Statistics()->getChannelFieldValue(TYPE_DC, channel, FLD_UDC);
|
||||||
|
|
||||||
if (dcVoltage <= 0.0) {
|
if (dcVoltage <= 0.0) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user