Feature: DPL: support overscaling on all inverters (#1286)
this change allows to support overscaling for all inverters, as the configuration of inputs (which one is part of a particular MPPT) is now provided from withing the code. this information is used to implement overscaling for any of the inverters (which are generally compatible with OpenDTU(-OnBattery)).
This commit is contained in:
parent
4524c0405d
commit
cf4a59c740
@ -29,6 +29,10 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A }
|
||||||
|
};
|
||||||
|
|
||||||
HERF_1CH::HERF_1CH(HoymilesRadio* radio, const uint64_t serial)
|
HERF_1CH::HERF_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HM_Abstract(radio, serial) {};
|
: HM_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -53,3 +57,13 @@ uint8_t HERF_1CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HERF_1CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HERF_1CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,6 +36,11 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_B }
|
||||||
|
};
|
||||||
|
|
||||||
HERF_2CH::HERF_2CH(HoymilesRadio* radio, const uint64_t serial)
|
HERF_2CH::HERF_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HM_Abstract(radio, serial) {};
|
: HM_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -60,3 +65,13 @@ uint8_t HERF_2CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HERF_2CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HERF_2CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,6 +28,10 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A }
|
||||||
|
};
|
||||||
|
|
||||||
HMS_1CH::HMS_1CH(HoymilesRadio* radio, const uint64_t serial)
|
HMS_1CH::HMS_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMS_Abstract(radio, serial) {};
|
: HMS_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -52,3 +56,13 @@ uint8_t HMS_1CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMS_1CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMS_1CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -11,4 +11,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -28,6 +28,10 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A }
|
||||||
|
};
|
||||||
|
|
||||||
HMS_1CHv2::HMS_1CHv2(HoymilesRadio* radio, const uint64_t serial)
|
HMS_1CHv2::HMS_1CHv2(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMS_Abstract(radio, serial) {};
|
: HMS_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -52,3 +56,13 @@ uint8_t HMS_1CHv2::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMS_1CHv2::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMS_1CHv2::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -11,4 +11,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -35,6 +35,11 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_B }
|
||||||
|
};
|
||||||
|
|
||||||
HMS_2CH::HMS_2CH(HoymilesRadio* radio, const uint64_t serial)
|
HMS_2CH::HMS_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMS_Abstract(radio, serial) {};
|
: HMS_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -59,3 +64,13 @@ uint8_t HMS_2CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMS_2CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMS_2CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -11,4 +11,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -49,6 +49,13 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_B },
|
||||||
|
{ CH2, MPPT_C },
|
||||||
|
{ CH3, MPPT_D }
|
||||||
|
};
|
||||||
|
|
||||||
HMS_4CH::HMS_4CH(HoymilesRadio* radio, const uint64_t serial)
|
HMS_4CH::HMS_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMS_Abstract(radio, serial) {};
|
: HMS_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -73,3 +80,13 @@ uint8_t HMS_4CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMS_4CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMS_4CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -58,6 +58,13 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_A },
|
||||||
|
{ CH2, MPPT_B },
|
||||||
|
{ CH3, MPPT_B }
|
||||||
|
};
|
||||||
|
|
||||||
HMT_4CH::HMT_4CH(HoymilesRadio* radio, const uint64_t serial)
|
HMT_4CH::HMT_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMT_Abstract(radio, serial) {};
|
: HMT_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -82,3 +89,13 @@ uint8_t HMT_4CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMT_4CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMT_4CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -72,6 +72,15 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_A },
|
||||||
|
{ CH2, MPPT_B },
|
||||||
|
{ CH3, MPPT_B },
|
||||||
|
{ CH4, MPPT_C },
|
||||||
|
{ CH5, MPPT_C }
|
||||||
|
};
|
||||||
|
|
||||||
HMT_6CH::HMT_6CH(HoymilesRadio* radio, const uint64_t serial)
|
HMT_6CH::HMT_6CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HMT_Abstract(radio, serial) {};
|
: HMT_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -96,3 +105,13 @@ uint8_t HMT_6CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HMT_6CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HMT_6CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -28,6 +28,10 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A }
|
||||||
|
};
|
||||||
|
|
||||||
HM_1CH::HM_1CH(HoymilesRadio* radio, const uint64_t serial)
|
HM_1CH::HM_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HM_Abstract(radio, serial) {};
|
: HM_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -65,3 +69,13 @@ uint8_t HM_1CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HM_1CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HM_1CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -11,4 +11,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -36,6 +36,11 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_B }
|
||||||
|
};
|
||||||
|
|
||||||
HM_2CH::HM_2CH(HoymilesRadio* radio, const uint64_t serial)
|
HM_2CH::HM_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HM_Abstract(radio, serial) {};
|
: HM_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -73,3 +78,13 @@ uint8_t HM_2CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HM_2CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HM_2CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -49,6 +49,13 @@ static const byteAssign_t byteAssignment[] = {
|
|||||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const channelMetaData_t channelMetaData[] = {
|
||||||
|
{ CH0, MPPT_A },
|
||||||
|
{ CH1, MPPT_A },
|
||||||
|
{ CH2, MPPT_B },
|
||||||
|
{ CH3, MPPT_B }
|
||||||
|
};
|
||||||
|
|
||||||
HM_4CH::HM_4CH(HoymilesRadio* radio, const uint64_t serial)
|
HM_4CH::HM_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||||
: HM_Abstract(radio, serial) {};
|
: HM_Abstract(radio, serial) {};
|
||||||
|
|
||||||
@ -86,3 +93,13 @@ uint8_t HM_4CH::getByteAssignmentSize() const
|
|||||||
{
|
{
|
||||||
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
return sizeof(byteAssignment) / sizeof(byteAssignment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const channelMetaData_t* HM_4CH::getChannelMetaData() const
|
||||||
|
{
|
||||||
|
return channelMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HM_4CH::getChannelMetaDataSize() const
|
||||||
|
{
|
||||||
|
return sizeof(channelMetaData) / sizeof(channelMetaData[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -10,4 +10,6 @@ public:
|
|||||||
String typeName() const;
|
String typeName() const;
|
||||||
const byteAssign_t* getByteAssignment() const;
|
const byteAssign_t* getByteAssignment() const;
|
||||||
uint8_t getByteAssignmentSize() const;
|
uint8_t getByteAssignmentSize() const;
|
||||||
|
const channelMetaData_t* getChannelMetaData() const;
|
||||||
|
uint8_t getChannelMetaDataSize() const;
|
||||||
};
|
};
|
||||||
@ -298,3 +298,35 @@ void InverterAbstract::resetRadioStats()
|
|||||||
{
|
{
|
||||||
RadioStats = {};
|
RadioStats = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ChannelNum_t> InverterAbstract::getChannelsDC() const
|
||||||
|
{
|
||||||
|
std::vector<ChannelNum_t> l;
|
||||||
|
for (uint8_t i = 0; i < getChannelMetaDataSize(); i++) {
|
||||||
|
l.push_back(getChannelMetaData()[i].ch);
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<MpptNum_t> InverterAbstract::getMppts() const
|
||||||
|
{
|
||||||
|
std::vector<MpptNum_t> l;
|
||||||
|
for (uint8_t i = 0; i < getChannelMetaDataSize(); i++) {
|
||||||
|
auto m = getChannelMetaData()[i].mppt;
|
||||||
|
if (l.end() == std::find(l.begin(), l.end(), m)){
|
||||||
|
l.push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ChannelNum_t> InverterAbstract::getChannelsDCByMppt(const MpptNum_t mppt) const
|
||||||
|
{
|
||||||
|
std::vector<ChannelNum_t> l;
|
||||||
|
for (uint8_t i = 0; i < getChannelMetaDataSize(); i++) {
|
||||||
|
if (getChannelMetaData()[i].mppt == mppt) {
|
||||||
|
l.push_back(getChannelMetaData()[i].ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|||||||
@ -24,6 +24,20 @@ enum {
|
|||||||
FRAGMENT_OK = 0
|
FRAGMENT_OK = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MpptNum_t {
|
||||||
|
MPPT_A = 0,
|
||||||
|
MPPT_B,
|
||||||
|
MPPT_C,
|
||||||
|
MPPT_D,
|
||||||
|
MPPT_CNT
|
||||||
|
};
|
||||||
|
|
||||||
|
// additional meta data per input channel
|
||||||
|
typedef struct {
|
||||||
|
ChannelNum_t ch; // channel 0 - 5
|
||||||
|
MpptNum_t mppt; // mppt a - d (0 - 3)
|
||||||
|
} channelMetaData_t;
|
||||||
|
|
||||||
#define MAX_RF_FRAGMENT_COUNT 13
|
#define MAX_RF_FRAGMENT_COUNT 13
|
||||||
|
|
||||||
class CommandAbstract;
|
class CommandAbstract;
|
||||||
@ -40,6 +54,9 @@ public:
|
|||||||
virtual const byteAssign_t* getByteAssignment() const = 0;
|
virtual const byteAssign_t* getByteAssignment() const = 0;
|
||||||
virtual uint8_t getByteAssignmentSize() const = 0;
|
virtual uint8_t getByteAssignmentSize() const = 0;
|
||||||
|
|
||||||
|
virtual const channelMetaData_t* getChannelMetaData() const = 0;
|
||||||
|
virtual uint8_t getChannelMetaDataSize() const = 0;
|
||||||
|
|
||||||
bool isProducing();
|
bool isProducing();
|
||||||
bool isReachable();
|
bool isReachable();
|
||||||
|
|
||||||
@ -112,6 +129,10 @@ public:
|
|||||||
StatisticsParser* Statistics();
|
StatisticsParser* Statistics();
|
||||||
SystemConfigParaParser* SystemConfigPara();
|
SystemConfigParaParser* SystemConfigPara();
|
||||||
|
|
||||||
|
std::vector<MpptNum_t> getMppts() const;
|
||||||
|
std::vector<ChannelNum_t> getChannelsDC() const;
|
||||||
|
std::vector<ChannelNum_t> getChannelsDCByMppt(const MpptNum_t mppt) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HoymilesRadio* _radio;
|
HoymilesRadio* _radio;
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include "PowerLimiterInverter.h"
|
#include "PowerLimiterInverter.h"
|
||||||
#include "PowerLimiterBatteryInverter.h"
|
#include "PowerLimiterBatteryInverter.h"
|
||||||
#include "PowerLimiterSolarInverter.h"
|
#include "PowerLimiterSolarInverter.h"
|
||||||
#include "inverters/HMS_4CH.h"
|
|
||||||
|
|
||||||
std::unique_ptr<PowerLimiterInverter> PowerLimiterInverter::create(
|
std::unique_ptr<PowerLimiterInverter> PowerLimiterInverter::create(
|
||||||
bool verboseLogging, PowerLimiterInverterConfig const& config)
|
bool verboseLogging, PowerLimiterInverterConfig const& config)
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "MessageOutput.h"
|
#include "MessageOutput.h"
|
||||||
#include "PowerLimiterSolarInverter.h"
|
#include "PowerLimiterSolarInverter.h"
|
||||||
#include "inverters/HMS_4CH.h"
|
|
||||||
|
|
||||||
PowerLimiterSolarInverter::PowerLimiterSolarInverter(bool verboseLogging, PowerLimiterInverterConfig const& config)
|
PowerLimiterSolarInverter::PowerLimiterSolarInverter(bool verboseLogging, PowerLimiterInverterConfig const& config)
|
||||||
: PowerLimiterInverter(verboseLogging, config) { }
|
: PowerLimiterInverter(verboseLogging, config) { }
|
||||||
@ -73,16 +72,13 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts)
|
|||||||
if (!isProducing()) { return expectedOutputWatts; }
|
if (!isProducing()) { return expectedOutputWatts; }
|
||||||
|
|
||||||
auto pStats = _spInverter->Statistics();
|
auto pStats = _spInverter->Statistics();
|
||||||
std::list<ChannelNum_t> dcChnls = pStats->getChannelsByType(TYPE_DC);
|
std::vector<ChannelNum_t> dcChnls = _spInverter->getChannelsDC();
|
||||||
|
std::vector<MpptNum_t> dcMppts = _spInverter->getMppts();
|
||||||
size_t dcTotalChnls = dcChnls.size();
|
size_t dcTotalChnls = dcChnls.size();
|
||||||
|
size_t dcTotalMppts = dcMppts.size();
|
||||||
|
|
||||||
// according to the upstream projects README (table with supported devs),
|
// if there is only one MPPT available, there is nothing we can do
|
||||||
// every 2 channel inverter has 2 MPPTs. then there are the HM*S* 4 channel
|
if (dcTotalMppts <= 1) { return expectedOutputWatts; }
|
||||||
// models which have 4 MPPTs. all others have a different number of MPPTs
|
|
||||||
// than inputs. those are not supported by the current scaling mechanism.
|
|
||||||
bool supported = dcTotalChnls == 2;
|
|
||||||
supported |= dcTotalChnls == 4 && HMS_4CH::isValidSerial(getSerial());
|
|
||||||
if (!supported) { return expectedOutputWatts; }
|
|
||||||
|
|
||||||
// test for a reasonable power limit that allows us to assume that an input
|
// test for a reasonable power limit that allows us to assume that an input
|
||||||
// channel with little energy is actually not producing, rather than
|
// channel with little energy is actually not producing, rather than
|
||||||
@ -101,37 +97,42 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts)
|
|||||||
inverterEfficiencyFactor = (inverterEfficiencyFactor > 0) ? inverterEfficiencyFactor/100 : 0.967;
|
inverterEfficiencyFactor = (inverterEfficiencyFactor > 0) ? inverterEfficiencyFactor/100 : 0.967;
|
||||||
|
|
||||||
// 98% of the expected power is good enough
|
// 98% of the expected power is good enough
|
||||||
auto expectedAcPowerPerChannel = (getCurrentLimitWatts() / dcTotalChnls) * 0.98;
|
auto expectedAcPowerPerMppt = (getCurrentLimitWatts() / dcTotalMppts) * 0.98;
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
MessageOutput.printf("%s expected AC power per channel %f W\r\n",
|
MessageOutput.printf("%s expected AC power per mppt %f W\r\n",
|
||||||
_logPrefix, expectedAcPowerPerChannel);
|
_logPrefix, expectedAcPowerPerMppt);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dcShadedChnls = 0;
|
size_t dcShadedMppts = 0;
|
||||||
auto shadedChannelACPowerSum = 0.0;
|
auto shadedChannelACPowerSum = 0.0;
|
||||||
|
|
||||||
for (auto& c : dcChnls) {
|
for (auto& m : dcMppts) {
|
||||||
auto channelPowerAC = pStats->getChannelFieldValue(TYPE_DC, c, FLD_PDC) * inverterEfficiencyFactor;
|
float mpptPowerAC = 0.0;
|
||||||
|
std::vector<ChannelNum_t> mpptChnls = _spInverter->getChannelsDCByMppt(m);
|
||||||
|
|
||||||
if (channelPowerAC < expectedAcPowerPerChannel) {
|
for (auto& c : mpptChnls) {
|
||||||
dcShadedChnls++;
|
mpptPowerAC += pStats->getChannelFieldValue(TYPE_DC, c, FLD_PDC) * inverterEfficiencyFactor;
|
||||||
shadedChannelACPowerSum += channelPowerAC;
|
}
|
||||||
|
|
||||||
|
if (mpptPowerAC < expectedAcPowerPerMppt) {
|
||||||
|
dcShadedMppts++;
|
||||||
|
shadedChannelACPowerSum += mpptPowerAC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
MessageOutput.printf("%s ch %d AC power %f W\r\n",
|
MessageOutput.printf("%s mppt-%c AC power %f W\r\n",
|
||||||
_logPrefix, c, channelPowerAC);
|
_logPrefix, m + 'a', mpptPowerAC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no shading or the shaded channels provide more power than what
|
// no shading or the shaded channels provide more power than what
|
||||||
// we currently need.
|
// we currently need.
|
||||||
if (dcShadedChnls == 0 || shadedChannelACPowerSum >= expectedOutputWatts) {
|
if (dcShadedMppts == 0 || shadedChannelACPowerSum >= expectedOutputWatts) {
|
||||||
return expectedOutputWatts;
|
return expectedOutputWatts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dcShadedChnls == dcTotalChnls) {
|
if (dcShadedMppts == dcTotalMppts) {
|
||||||
// keep the currentLimit when:
|
// keep the currentLimit when:
|
||||||
// - all channels are shaded
|
// - all channels are shaded
|
||||||
// - currentLimit >= expectedOutputWatts
|
// - currentLimit >= expectedOutputWatts
|
||||||
@ -139,7 +140,7 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts)
|
|||||||
if (getCurrentLimitWatts() >= expectedOutputWatts &&
|
if (getCurrentLimitWatts() >= expectedOutputWatts &&
|
||||||
inverterOutputAC <= expectedOutputWatts) {
|
inverterOutputAC <= expectedOutputWatts) {
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
MessageOutput.printf("%s all channels are shaded, "
|
MessageOutput.printf("%s all mppts are shaded, "
|
||||||
"keeping the current limit of %d W\r\n",
|
"keeping the current limit of %d W\r\n",
|
||||||
_logPrefix, getCurrentLimitWatts());
|
_logPrefix, getCurrentLimitWatts());
|
||||||
}
|
}
|
||||||
@ -151,31 +152,38 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dcNonShadedChnls = dcTotalChnls - dcShadedChnls;
|
size_t dcNonShadedMppts = dcTotalMppts - dcShadedMppts;
|
||||||
uint16_t overScaledLimit = (expectedOutputWatts - shadedChannelACPowerSum) / dcNonShadedChnls * dcTotalChnls;
|
uint16_t overScaledLimit = (expectedOutputWatts - shadedChannelACPowerSum) / dcNonShadedMppts * dcTotalMppts;
|
||||||
|
|
||||||
if (overScaledLimit <= expectedOutputWatts) { return expectedOutputWatts; }
|
if (overScaledLimit <= expectedOutputWatts) { return expectedOutputWatts; }
|
||||||
|
|
||||||
if (_verboseLogging) {
|
if (_verboseLogging) {
|
||||||
MessageOutput.printf("%s %d/%d channels are shaded, scaling %d W\r\n",
|
MessageOutput.printf("%s %d/%d mppts are shaded, scaling %d W\r\n",
|
||||||
_logPrefix, dcShadedChnls, dcTotalChnls, overScaledLimit);
|
_logPrefix, dcShadedMppts, dcTotalMppts, overScaledLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
return overScaledLimit;
|
return overScaledLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dcProdChnls = 0;
|
size_t dcProdMppts = 0;
|
||||||
for (auto& c : dcChnls) {
|
for (auto& m : dcMppts) {
|
||||||
if (pStats->getChannelFieldValue(TYPE_DC, c, FLD_PDC) > 2.0) {
|
float dcPowerMppt = 0.0;
|
||||||
dcProdChnls++;
|
std::vector<ChannelNum_t> mpptChnls = _spInverter->getChannelsDCByMppt(m);
|
||||||
|
|
||||||
|
for (auto& c : mpptChnls) {
|
||||||
|
dcPowerMppt += pStats->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcPowerMppt > 2.0 * mpptChnls.size()) {
|
||||||
|
dcProdMppts++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dcProdChnls == 0 || dcProdChnls == dcTotalChnls) { return expectedOutputWatts; }
|
if (dcProdMppts == 0 || dcProdMppts == dcTotalMppts) { return expectedOutputWatts; }
|
||||||
|
|
||||||
uint16_t scaled = expectedOutputWatts / dcProdChnls * dcTotalChnls;
|
uint16_t scaled = expectedOutputWatts / dcProdMppts * dcTotalMppts;
|
||||||
MessageOutput.printf("%s %d/%d channels are producing, scaling from %d to "
|
MessageOutput.printf("%s %d/%d mppts are producing, scaling from %d to "
|
||||||
"%d W\r\n", _logPrefix, dcProdChnls, dcTotalChnls,
|
"%d W\r\n", _logPrefix, dcProdMppts, dcTotalMppts,
|
||||||
expectedOutputWatts, scaled);
|
expectedOutputWatts, scaled);
|
||||||
|
|
||||||
return scaled;
|
return scaled;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user