Skip to content

Commit

Permalink
added GridProfileParser from noone2k
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan123t committed Nov 26, 2023
1 parent 859b902 commit 281e76f
Show file tree
Hide file tree
Showing 2 changed files with 300 additions and 0 deletions.
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;
}
214 changes: 214 additions & 0 deletions 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_structs = {
{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, {
{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"}
}},
{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"}
}},
{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, {
{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"}
}},
{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
}}
}},
{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, {
{0x02, {
{"APC Function Activated", "bool", "1"},
{"Power Ramp Rate (PRR)", "Pn%/s", "100"}
}},
{0x00, {
{"APC Function Activated", "bool", "1"}
}}
}},
{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"}
}}
}}
};
};

0 comments on commit 281e76f

Please sign in to comment.