#include <Arduino.h>
#include <map>
#include <vector>
#include <WiFi.h>
std::map<String, int> dataMap; // Map to store data from all sources
struct labelsAndUnits
{
String displayName;
String unit;
int conversionFactor;
};
// Map value labels to human-readable names
const std::map<String, labelsAndUnits> labelMapping{
{"TIMESTAMP", {"Unix-tid", "s", 1}},
{"ENV_REFRIG_TEMP", {"Temperatur, kyl", "°C", 1}},
{"ENV_ROOM_TEMP", {"Temperatur, rum", "°C", 1}},
{"ENV_ROOM_HUMID", {"Luftfuktighet, rum", "%RH", 1}},
{"VE_MPPT_PPV", {"Paneleffekt", "W", 1}},
{"VE_MPPT_VPV", {"Panelspänning", "V", 1000}},
{"VE_MPPT_I", {"Laddström", "A", 1000}},
{"VE_MPPT_V", {"Batterispänning (laddningsregulator)", "V", 1000}},
{"VE_MPPT_H19", {"Total avkastning", "kWh", 100}},
{"VE_MPPT_H20", {"Avkastning idag", "kWh", 100}},
{"VE_MPPT_H21", {"Max. effekt idag", "W", 1}},
{"VE_MPPT_H22", {"Avkastning igår", "kWh", 100}},
{"VE_MPPT_H23", {"Max. effekt igår", "W", 1}},
{"VE_MPPT_HSDS", {"Dagsnummer", "", 1}},
{"VE_INV_V", {"Batterispänning (växelriktare)", "V", 1000}},
{"VE_INV_AC_OUT_S", {"Effekt, växelström", "VA", 1}},
{"VE_INV_AC_OUT_I", {"Strömstyrka, växelström", "A", 10}},
{"VE_INV_AC_OUT_V", {"Spänning, växelström", "V", 100}},
{"VE_MPPT_MPPT", {"Spårningsläge", "", 0}},
{"VE_INV_Relay", {"Reläläge (växelriktare)", "", 0}},
{"VE_MPPT_Relay", {"Reläläge (laddningsregulator)", "", 0}},
{"VE_MPPT_CS", {"Driftsläge (laddningsregulator)", "", 0}},
{"VE_INV_CS", {"Driftstillstånd (växelriktare)", "", 0}},
{"VE_MPPT_ERR", {"Felkod (laddningsregulator)", "", 0}},
{"VE_INV_MODE", {"Driftsläge (växelriktare)", "", 0}},
{"VE_INV_OR", {"Av-orsak (växelriktare)", "", 0}},
{"VE_INV_AR", {"Larmorsak (växelriktare)", "", 0}},
{"VE_INV_WARN", {"Felorsak (växelriktare)", "", 0}},
};
const std::map<const String, std::map<const int, const String>> LabelCodeMapping {
{"VE_MPPT_Relay",
{
{0, "Av"},
{1, "På"},
}},
{"VE_INV_Relay",
{
{0, "Av"},
{1, "På"},
}},
{"VE_INV_AR",
{
{1, "Låg spänning"},
{2, "Hög spänning"},
{32, "Låg temperatur"},
{64, "Hög temperatur"},
{256, "Överbelastning"},
{512, "DC-rippel"},
{1024, "Låg V AC ut"},
{2048, "Hög V AC ut"},
}},
{"VE_MPPT_MPPT",
{
{0, "Av"},
{1, "Spänning eller ström begränsad"},
{2, "MPPT-spårare aktiv"},
}},
{"VE_MPPT_CS",
{
{0, "Avstängd"},
{2, "Fel"},
{3, "Bulk"},
{4, "Absorbtion"},
{5, "Float"},
{7, "Utjämna (manuell)"},
{254, "Startar"},
{247, "Auto-utjämning"},
{252, "Extern styrning"},
}},
{"VE_INV_CS",
{
{0, "Avstängd"},
{1, "Söker last"},
{2, "Fel"},
{9, "Omvandlar"},
}},
{"VE_MPPT_ERR",
{
{0, "Inget fel"},
{2, "Batterispänning för hög"},
{17, "Laddaren för varm"},
{18, "Överström i laddaren"},
{19, "Laddström omvänd"},
{20, "Bulk-tidsgräns nådd"},
{21, "Strömsensor defekt"},
{26, "Terminaler överhettade"},
{28, "Problem med omvandlaren"},
{33, "Ingående spänning för hög"},
{34, "Ingående ström för hög"},
{38, "Ingående ström avstängd p.g.a. hög batterispänning"},
{39, "Ingående ström avstängd p.g.a. ström under avstängt läge"},
{65, "Tappat kontakten med någon enhet"},
{66, "Problem med synkroniserade laddningsenhet"},
{67, "Tappat kontakt med BMS"},
{68, "Nätverk felkonfigurerat"},
{116, "Förlorat fabrikskonfiguration"},
{117, "Fel i den fasta programvaran"},
{119, "Fel i instälningar"},
}},
{"VE_INV_WARN",
{
{0, "Inget fel"},
{2, "Batterispänning för hög"},
{17, "Laddaren för varm"},
{18, "Överström i laddaren"},
{19, "Laddström omvänd"},
{20, "Bulk-tidsgräns nådd"},
{21, "Strömsensor defekt"},
{26, "Terminaler överhettade"},
{28, "Problem med omvandlaren"},
{33, "Ingående spänning för hög"},
{34, "Ingående ström för hög"},
{38, "Ingående ström avstängd p.g.a. hög batterispänning"},
{39, "Ingående ström avstängd p.g.a. ström under avstängt läge"},
{65, "Tappat kontakten med någon enhet"},
{66, "Problem med synkroniserade laddningsenhet"},
{67, "Tappat kontakt med BMS"},
{68, "Nätverk felkonfigurerat"},
{116, "Förlorat fabrikskonfiguration"},
{117, "Fel i den fasta programvaran"},
{119, "Fel i instälningar"},
}},
{"VE_INV_MODE",
{
{2, "Omvandlar"},
{4, "Av"},
{5, "Eco"},
}},
{"VE_INV_OR",
{
{0x00000001, "Ingen inkommande ström"},
{0x00000002, "Avstängd (brytare)"},
{0x00000004, "Avstängd (lägesinställning)"},
{0x00000008, "Fjärrkontroll"},
{0x00000010, "Skydd aktiverat"},
{0x00000020, "Paygo"},
{0x00000040, "BMS"},
{0x00000080, "Motor avstängd"},
{0x00000100, "Analyserar inkommande spänning"},
}},
};
String convertMessageCode(String label, int code);
std::vector<int> getMessageCodeVectorFromSum(String label, int ReceivedCode);
std::vector<int> findCombination(const std::vector<int>& series, int code);
void writeToLog(String message, String status = "ERROR") {
Serial.println(message);
}
int n = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
// Reset data map
dataMap.clear();
Serial.println("Contents of dataMap: #############################");
for (auto const &entry : dataMap)
{
String label = entry.first;
float value = entry.second;
Serial.print(label);
Serial.print("\t");
Serial.println(value);
}
Serial.print("Meddelandekod: ");
Serial.println(n);
Serial.println(convertMessageCode("VE_INV_CS", n));
n++;
delay(2000);
}
String convertMessageCode(String label, int ReceivedCode) // Recieves a label representing message type and a code representing one or more messages
{
try
{
const std::map<const int, const String> &CodeToMessageMappings = LabelCodeMapping.at(label); // Get the code-to-message mapping for this 'label'
String ConcatenatedMessage;
if (CodeToMessageMappings.count(ReceivedCode) > 0) // If the message code is an exact match, there is only one message and we can return that
{
ConcatenatedMessage = CodeToMessageMappings.at(ReceivedCode);
Serial.print("Hittade exact match för ");
Serial.println(ReceivedCode);
return ConcatenatedMessage;
}
// If no exact match, extract individual messages using maths
// Gather all codes for this label
std::vector<int> AvailableCodes;
for (const auto& entry : CodeToMessageMappings) {
AvailableCodes.push_back(entry.first);
}
// Get a vector of all codes that are summed to make up 'RecievedCode'
std::vector <int> CodesInMessage = findCombination(AvailableCodes, ReceivedCode);
if (CodesInMessage.empty()) {
throw std::logic_error("Code recieved from VE.Direct does not exactly match message table");
}
for (int ThisCode : CodesInMessage)
{
if (ConcatenatedMessage != "") // If this is not the first message, add comma and space before
{
ConcatenatedMessage += ", ";
}
ConcatenatedMessage += CodeToMessageMappings.at(ThisCode);
}
/*
int RemainingCode = ReceivedCode;
Serial.print("Bryter up ");
Serial.println(ReceivedCode);
for (auto entry = CodeToMessageMappings.rbegin(); entry != CodeToMessageMappings.rend() && entry->first != 0; ++entry) // Iterate over the map in reverse order, ignore 0
{
if (RemainingCode >= entry->first) // If the code we're testing is included in the recieved message
{
Serial.print("Meddelande hittades för ");
Serial.print(entry->first);
Serial.print(" (");
Serial.print(entry->second);
Serial.println(").");
if (ConcatenatedMessage != "") // If this is not the first message, add comma and space before
{
ConcatenatedMessage += ", ";
}
ConcatenatedMessage += entry->second; // Add the message
RemainingCode -= entry->first; // Remove this code from the int
}
}
if (RemainingCode > 0)
{
Serial.print("Skräp i felkoden: ");
Serial.println(RemainingCode);
throw std::logic_error("Code recieved from VE.Direct does not exactly match message table");
}*/
return ConcatenatedMessage;
}
catch (const std::out_of_range &e) // There is no entry for this label in 'LabelCodeMapping'
{
String ErrorMessage = "Hittade inga meddelanden för " + label;
writeToLog(ErrorMessage);
writeToLog(e.what());
return ErrorMessage;
}
catch (const std::runtime_error &e) // There is an entry, but it is empty
{
String ErrorMessage = "Hittade inget meddelanden för kod " + String(ReceivedCode) + " för " + label ;
writeToLog(ErrorMessage);
writeToLog(e.what());
return ErrorMessage;
}
catch (const std::logic_error &e) // Extracted a code that doesn't have an entry
{
String ErrorMessage = "Felaktig meddelandekod " + String(ReceivedCode) + " för " + label ;
writeToLog(ErrorMessage);
writeToLog(e.what());
return ErrorMessage;
}
}
// Function to find the combination of numbers from the series that sum up to the given code
std::vector<int> findCombination(const std::vector<int>& series, int code) {
// Get the size of the series
int seriesSize = series.size();
// Initialize a 2D array to store the dynamic programming table
bool dp[seriesSize + 1][code + 1];
// Initialize the first column of the table
for (int i = 0; i <= seriesSize; i++) {
dp[i][0] = true;
}
// Initialize the first row of the table
for (int j = 1; j <= code; j++) {
dp[0][j] = false;
}
// Fill the dynamic programming table
for (int i = 1; i <= seriesSize; i++) {
for (int j = 1; j <= code; j++) {
// If the current element is greater than the sum, it cannot be included
if (series[i - 1] > j) {
dp[i][j] = dp[i - 1][j];
}
// Otherwise, consider including or excluding the current element
else {
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - series[i - 1]];
}
}
}
// Check if there is a valid combination for the given code
if (!dp[seriesSize][code]) {
// No valid combination found, return an empty vector
return std::vector<int>();
}
// Reconstruct the combination from the dynamic programming table
std::vector<int> combination;
int i = seriesSize;
int j = code;
while (i > 0 && j > 0) {
if (dp[i][j] && !dp[i - 1][j]) {
// Include the current element in the combination
combination.push_back(series[i - 1]);
j -= series[i - 1];
}
i--;
}
return combination;
}
Loading
esp32-devkit-c-v4
esp32-devkit-c-v4