Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added GridProfileParser from noone2k #1527

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions lib/Hoymiles/src/parser/GridProfileParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "GridProfileParser.h"
#include "../Hoymiles.h"
#include <cstring>
#include <iostream>

GridProfileParser::GridProfileParser()
: Parser()
Expand Down Expand Up @@ -38,3 +39,88 @@ std::vector<uint8_t> GridProfileParser::getRawData()
HOY_SEMAPHORE_GIVE();
return ret;
}


int GridProfileParser::modbusCrc(std::string msg) {
int crc = 0xFFFF;
for (int n = 0; n < msg.length(); n++) {
crc ^= msg[n];
for (int i = 0; i < 8; i++) {
if (crc & 1) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}

std::string GridProfileParser::parseGridProfile(std::string hex_string) {

std::vector<unsigned char> binary_string;
for (int i = 0; i < hex_string.length(); i += 2) {
std::string byte_string = hex_string.substr(i, 2);
unsigned char byte = std::stoi(byte_string, nullptr, 16);
binary_string.push_back(byte);
}
int binary_length = binary_string.size();

int str_header1 = binary_string[0];
int str_header2 = binary_string[1];
int str_version1 = binary_string[2];
int str_version2 = binary_string[3];

try {
std::cout << "Grid Profile: " << profile_types[str_header1][str_header2] << std::endl;
} catch (...) {
std::cout << "Grid Profile: unknown" << std::endl;
}

std::cout << "Version: " << ((str_version1 >> 4) & 0x0F) << "." << (str_version1 & 0x0F) << "." << str_version2 << std::endl;

int position = 4;
while (position < binary_length) {
int str_table_n = binary_string[position];
int str_table_v = binary_string[position + 1];

try {
std::cout << "Table Type: " << profile_structs[str_table_n] << std::endl;
} catch (...) {
// pass
}

try {
std::vector<std::vector<std::string>> tables_diz = profile_details[str_table_n][str_table_v];
int table_length = tables_diz.size();

position += 2;
for (int x = 0; x < table_length; x++) {
std::vector<std::string> table_diz = tables_diz[x];
int str_int = (binary_string[position] << 8) | binary_string[position + 1];
float str_val = str_int / std::stof(table_diz[2]);

std::cout << "position: " << position << "\t: " << std::hex << str_int << "\t" << std::dec << str_val << "\t[" << table_diz[1] << "]\t\t[" << table_diz[0] << "]" << std::endl;
position += 2;
}
} catch (...) {
std::string crc = std::to_string(binary_string[position]) + std::to_string(binary_string[position + 1]);
int crc2 = modbusCrc(hex_string.substr(0, position));
std::string crcc = std::to_string(crc2);

if (crc == crcc) {
std::cout << "CRC (ok): " << crcc << std::endl;
} else {
std::cout << "CRC (?): " << crc << std::endl;
std::cout << "CRC calced: " << crcc << std::endl;
std::cout << " - possible unknown table (module)" << std::endl;
}

std::cout << "end" << std::endl;
break;
}
}

return 0;
}
216 changes: 215 additions & 1 deletion lib/Hoymiles/src/parser/GridProfileParser.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "Parser.h"
#include <map>
#include <vector>

#define GRID_PROFILE_SIZE 141

Expand All @@ -11,8 +13,220 @@ class GridProfileParser : public Parser {
void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len);

std::vector<uint8_t> getRawData();
int GridProfileParser::modbusCrc(std::string msg);
std::string parseGridProfile(std::string hex_string);

private:
uint8_t _payloadGridProfile[GRID_PROFILE_SIZE] = {};
uint8_t _gridProfileLength = 0;
};

std::map<int, std::map<int, std::string>> profile_types = {
{0x02, {{0x00, "no data (yet)"}}},
{0x03, {{0x00, "Germany - DE_VDE4105_2018"}}},
{0x0a, {{0x00, "European - EN 50549-1:2019"}}},
{0x0c, {{0x00, "AT Tor - EU_EN50438"}}},
{0x0d, {{0x04, "France"}}},
{0x12, {{0x00, "Poland - EU_EN50438"}}},
{0x37, {{0x00, "Swiss - CH_NA EEA-NE7-CH2020"}}}
};

std::map<int, std::string> profile_sections = {
{0x00, "Voltage (H/LVRT)"},
{0x10, "Frequency (H/LFRT)"},
{0x20, "Island Detection (ID)"},
{0x30, "Reconnection (RT)"},
{0x40, "Ramp Rates (RR)"},
{0x50, "Frequency Watt (FW)"},
{0x60, "Volt Watt (VW)"},
{0x70, "Active Power Control (APC)"},
{0x80, "Volt Var (VV)"},
{0x90, "Specified Power Factor (SPF)"},
{0xA0, "Reactive Power Control (RPC)"},
{0xB0, "Watt Power Factor (WPF)"}
};

std::map<int, std::map<int, std::vector<std::vector<std::string>>>> profile_details = {
{0x00, {
{0x00, {
{"Nominale Voltage (NV)", "V", "10"},
{"Low Voltage 1 (LV1)", "V", "10"},
{"LV1 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 1 (HV1)", "V", "10"},
{"HV1 Maximum Trip Time (MTT)", "s", "10"}
}},
{0x03, {
{"Nominale Voltage (NV)", "V", "10"},
{"Low Voltage 1 (LV1)", "V", "10"},
{"LV1 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 1 (HV1)", "V", "10"},
{"HV1 Maximum Trip Time (MTT)", "s", "10"},
{"Low Voltage 2 (LV2)", "V", "10"},
{"LV2 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 2 (HV2)", "V", "10"},
{"HV2 Maximum Trip Time (MTT)", "s", "10"}
}},
{0x0A, {
{"Nominale Voltage (NV)", "V", "10"},
{"Low Voltage 1 (LV1)", "V", "10"},
{"LV1 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 1 (HV1)", "V", "10"},
{"HV1 Maximum Trip Time (MTT)", "s", "10"},
{"Low Voltage 2 (LV2)", "V", "10"},
{"LV2 Maximum Trip Time (MTT)", "s", "10"},
{"10mins Average High Voltage (AHV)", "V", "10"}
}},
{0x0B, {
{"Nominale Voltage (NV)", "V", "10"},
{"Low Voltage 1 (LV1)", "V", "10"},
{"LV1 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 1 (HV1)", "V", "10"},
{"HV1 Maximum Trip Time (MTT)", "s", "10"},
{"Low Voltage 2 (LV2)", "V", "10"},
{"LV2 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 2 (HV2)", "V", "10"},
{"HV2 Maximum Trip Time (MTT)", "s", "10"},
{"10mins Average High Voltage (AHV)", "V", "10"}
}},
{0x0C, {
{"Nominale Voltage (NV)", "V", "10"},
{"Low Voltage 1 (LV1)", "V", "10"},
{"LV1 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 1 (HV1)", "V", "10"},
{"HV1 Maximum Trip Time (MTT)", "s", "10"},
{"Low Voltage 2 (LV2)", "V", "10"},
{"LV2 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 2 (HV2)", "V", "10"},
{"HV2 Maximum Trip Time (MTT)", "s", "10"},
{"High Voltage 3 (HV3)", "V", "10"},
{"HV3 Maximum Trip Time (MTT)", "s", "10"},
{"10mins Average High Voltage (AHV)", "V", "10"}
}}
}},
{0x10, {
{0x00, {
{"Nominal Frequency", "Hz", "100"},
{"Low Frequency 1 (LF1)", "Hz", "100"},
{"LF1 Maximum Trip Time (MTT)", "s", "10"},
{"High Frequency 1 (HF1)", "Hz", "100"},
{"HF1 Maximum Trip time (MTT)", "s", "10"}
}},
{0x03, {
{"Nominal Frequency", "Hz", "100"},
{"Low Frequency 1 (LF1)", "Hz", "100"},
{"LF1 Maximum Trip Time (MTT)", "s", "10"},
{"High Frequency 1 (HF1)", "Hz", "100"},
{"HF1 Maximum Trip time (MTT)", "s", "10"},
{"Low Frequency 2 (LF2)", "Hz", "100"},
{"LF2 Maximum Trip Time (MTT)", "s", "10"},
{"High Frequency 2 (HF2)", "Hz", "100"},
{"HF2 Maximum Trip time (MTT)", "s", "10"}
}}
}},
{0x20, {
{0x00, {
{"ID Function Activated", "bool", "1"}
}}
}},
{0x30, {
{0x03, {
{"Reconnect Time (RT)", "s", "10"},
{"Reconnect High Voltage (RHV)", "V", "10"},
{"Reconnect Low Voltage (RLV)", "V", "10"},
{"Reconnect High Frequency (RHF)", "Hz", "100"},
{"Reconnect Low Frequency (RLF)", "Hz", "100"}
}}
}},
{0x40, {
{0x00, {
{"Normal Ramp up Rate(RUR_NM)", "Rated%/s", "100"},
{"Soft Start Ramp up Rate (RUR_SS)", "Rated%/s", "100"}
}}
}},
{0x50, {
{0x00, {
{"FW Function Activated", "bool", "1"},
{"Start of Frequency Watt Droop (Fstart)", "Hz", "100"},
{"FW Droop Slope (Kpower_Freq)", "Pn%/Hz", "10"},
{"Recovery Ramp Rate (RRR)", "Pn%/s", "100"}
}},
{0x01, {
{"FW Function Activated", "bool", "1"},
{"Start of Frequency Watt Droop (Fstart)", "Hz", "100"},
{"FW Droop Slope (Kpower_Freq)", "Pn%/Hz", "10"},
{"Recovery Ramp Rate (RRR)", "Pn%/s", "100"},
{"Recovery High Frequency (RVHF)", "Hz", "100"} // may need to be div 10
}},
{0x08, {
{"FW Function Activated", "bool", "1"},
{"Start of Frequency Watt Droop (Fstart)", "Hz", "100"},
{"FW Droop Slope (Kpower_Freq)", "Pn%/Hz", "10"},
{"Recovery Ramp Rate (RRR)", "Pn%/s", "100"},
{"Recovery High Frequency (RVHF)", "Hz", "100"}, // may need to be div 10
{"Recovery Low Frequency (RVLF)", "Hz", "100"}
}}
}},
{0x60, {
{0x00, {
{"VW Function Activated", "bool", "1"},
{"Start of Voltage Watt Droop (Vstart)", "V", "10"},
{"End of Voltage Watt Droop (Vend)", "V", "10"},
{"Droop Slope (Kpower_Volt)", "Pn%/V", "100"}
}},
{0x04, {
{"VW Function Activated", "bool", "1"},
{"Start of Voltage Watt Droop (Vstart)", "V", "10"},
{"End of Voltage Watt Droop (Vend)", "V", "10"},
{"Droop Slope (Kpower_Volt)", "Pn%/V", "100"}
}}
}},
{0x70, {
{0x00, {
{"APC Function Activated", "bool", "1"}
}},
{0x02, {
{"APC Function Activated", "bool", "1"},
{"Power Ramp Rate (PRR)", "Pn%/s", "100"}
}}
}},
{0x80, {
{0x00, {
{"VV Function Activated", "bool", "1"},
{"Voltage Set Point V1", "V", "10"},
{"Reactive Set Point Q1", "%Pn", "10"},
{"Voltage Set Point V2", "V", "10"},
{"Voltage Set Point V3", "V", "10"},
{"Voltage Set Point V4", "V", "10"},
{"Reactive Set Point Q4", "%Pn", "10"}
}},
{0x01, {
{"VV Function Activated", "bool", "1"},
{"Voltage Set Point V1", "V", "10"},
{"Reactive Set Point Q1", "%Pn", "10"},
{"Voltage Set Point V2", "V", "10"},
{"Voltage Set Point V3", "V", "10"},
{"Voltage Set Point V4", "V", "10"},
{"Reactive Set Point Q4", "%Pn", "10"},
{"Setting Time (Tr)", "s", "10"}
}}
}},
{0x90, {
{0x00, {
{"SPF Function Activated", "bool", "1"},
{"Power Factor (PF)", "", "100"}
}}
}},
{0xA0, {
{0x02, {
{"RPC Function Activated", "bool", "1"},
{"Reactive Power (VAR)", "%Sn", "1"}
}}
}},
{0xB0, {
{0x00, {
{"WPF Function Activated", "bool", "1"},
{"Start of Power of WPF (Pstart)", "%Pn", "10"},
{"Power Factor ar Rated Power (PFRP)", "", "100"}
}}
}}
};
};