Skip to content

Commit

Permalink
Fix: support configuring inverters with hex digits in serial
Browse files Browse the repository at this point in the history
even though the underlying radio communication should be able to handle
any inverter serial, since it is converted to uint64_t, the web
application and the respective API handlers in the firmware were not yet
ready to accept inverter serial numbers with actual hex digits (a-f) in
them.
  • Loading branch information
schlimmchen committed Mar 15, 2024
1 parent 2efa1b3 commit 3d96405
Show file tree
Hide file tree
Showing 12 changed files with 39 additions and 26 deletions.
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMS_1CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ HMS_1CH::HMS_1CH(HoymilesRadio* radio, const uint64_t serial)

bool HMS_1CH::isValidSerial(const uint64_t serial)
{
// serial >= 0x112400000000 && serial <= 0x112499999999
// serial >= 0x112400000000 && serial <= 0x1124ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1124;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMS_1CHv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ HMS_1CHv2::HMS_1CHv2(HoymilesRadio* radio, const uint64_t serial)

bool HMS_1CHv2::isValidSerial(const uint64_t serial)
{
// serial >= 0x112500000000 && serial <= 0x112599999999
// serial >= 0x112500000000 && serial <= 0x1125ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1125;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMS_2CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ HMS_2CH::HMS_2CH(HoymilesRadio* radio, const uint64_t serial)

bool HMS_2CH::isValidSerial(const uint64_t serial)
{
// serial >= 0x114400000000 && serial <= 0x114499999999
// serial >= 0x114400000000 && serial <= 0x1144ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1144;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMS_4CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ HMS_4CH::HMS_4CH(HoymilesRadio* radio, const uint64_t serial)

bool HMS_4CH::isValidSerial(const uint64_t serial)
{
// serial >= 0x116400000000 && serial <= 0x116499999999
// serial >= 0x116400000000 && serial <= 0x1164ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1164;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMT_4CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ HMT_4CH::HMT_4CH(HoymilesRadio* radio, const uint64_t serial)

bool HMT_4CH::isValidSerial(const uint64_t serial)
{
// serial >= 0x136100000000 && serial <= 0x136199999999
// serial >= 0x136100000000 && serial <= 0x1361ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1361;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Hoymiles/src/inverters/HMT_6CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ HMT_6CH::HMT_6CH(HoymilesRadio* radio, const uint64_t serial)

bool HMT_6CH::isValidSerial(const uint64_t serial)
{
// serial >= 0x138200000000 && serial <= 0x138299999999
// serial >= 0x138200000000 && serial <= 0x1382ffffffff
uint16_t preSerial = (serial >> 32) & 0xffff;
return preSerial == 0x1382;
}
Expand Down
26 changes: 17 additions & 9 deletions src/WebApi_inverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,14 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
return;
}

if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
// Interpret the string as a hex value and convert it to uint64_t
char* endPos;
auto serialString = root["serial"].as<String>();
uint64_t serial = strtoll(serialString.c_str(), &endPos, 16);
if (endPos != serialString.c_str() + serialString.length()) { serial = 0; }

if (serial == 0) {
retMsg["message"] = "Serial must (only) be a hexadecimal number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength();
request->send(response);
Expand All @@ -157,8 +163,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
return;
}

// Interpret the string as a hex value and convert it to uint64_t
inverter->Serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
inverter->Serial = serial;

strncpy(inverter->Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);

Expand Down Expand Up @@ -233,8 +238,14 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
return;
}

if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
// Interpret the string as a hex value and convert it to uint64_t
char* endPos;
auto serialString = root["serial"].as<String>();
uint64_t new_serial = strtoll(serialString.c_str(), &endPos, 16);
if (endPos != serialString.c_str() + serialString.length()) { new_serial = 0; }

if (new_serial == 0) {
retMsg["message"] = "Serial must (only) be a hexadecimal number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength();
request->send(response);
Expand All @@ -261,10 +272,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)

INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[root["id"].as<uint8_t>()];

uint64_t new_serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
uint64_t old_serial = inverter.Serial;

// Interpret the string as a hex value and convert it to uint64_t
inverter.Serial = new_serial;
strncpy(inverter.Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);

Expand Down
11 changes: 8 additions & 3 deletions src/WebApi_limit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,14 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
return;
}

if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
// Interpret the string as a hex value and convert it to uint64_t
char* endPos;
auto serialString = root["serial"].as<String>();
uint64_t serial = strtoll(serialString.c_str(), &endPos, 16);
if (endPos != serialString.c_str() + serialString.length()) { serial = 0; }

if (serial == 0) {
retMsg["message"] = "Serial must (only) be a hexadecimal number > 0!";
retMsg["code"] = WebApiError::LimitSerialZero;
response->setLength();
request->send(response);
Expand Down Expand Up @@ -129,7 +135,6 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
return;
}

uint64_t serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
uint16_t limit = root["limit_value"].as<uint16_t>();
PowerLimitControlType type = root["limit_type"].as<PowerLimitControlType>();

Expand Down
4 changes: 2 additions & 2 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"2005": "Ungültige Landesauswahl!",
"3001": "Nichts gelöscht!",
"3002": "Konfiguration zurückgesetzt. Starte jetzt neu...",
"4001": "@:apiresponse.2001",
"4001": "Die Wechselrichter-Seriennummer muss (ausschließlich) eine hexadezimale Zahl ungleich Null sein!",
"4002": "Der Name muss zwischen 1 und {max} Zeichen lang sein!",
"4003": "Es werden nur {max} Wechselrichter unterstützt!",
"4004": "Wechselrichter angelegt!",
Expand All @@ -69,7 +69,7 @@
"4007": "Wechselrichter geändert!",
"4008": "Wechselrichter gelöscht!",
"4009": "Wechselrichter Reihenfolge gespeichert!",
"5001": "@:apiresponse.2001",
"5001": "@:apiresponse.4001",
"5002": "Das Limit muss zwischen 1 und {max} sein!",
"5003": "Ungültiten Typ angegeben!",
"5004": "Ungültigen Inverter angegeben!",
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"2005": "Invalid country selection!",
"3001": "Not deleted anything!",
"3002": "Configuration resettet. Rebooting now...",
"4001": "@:apiresponse.2001",
"4001": "The inverter serial number must (only) be a hexadecimal number other than zero.",
"4002": "Name must between 1 and {max} characters long!",
"4003": "Only {max} inverters are supported!",
"4004": "Inverter created!",
Expand All @@ -69,7 +69,7 @@
"4007": "Inverter changed!",
"4008": "Inverter deleted!",
"4009": "Inverter order saved!",
"5001": "@:apiresponse.2001",
"5001": "@:apiresponse.4001",
"5002": "Limit must between 1 and {max}!",
"5003": "Invalid type specified!",
"5004": "Invalid inverter specified!",
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"2005": "Invalid country selection !",
"3001": "Rien n'a été supprimé !",
"3002": "Configuration réinitialisée. Redémarrage maintenant...",
"4001": "@:apiresponse.2001",
"4001": "Le numéro de série de l'onduleur doit (uniquement) être un nombre hexadécimal différent de zéro.",
"4002": "Le nom doit comporter entre 1 et {max} caractères !",
"4003": "Seulement {max} onduleurs sont supportés !",
"4004": "Onduleur créé !",
Expand All @@ -69,7 +69,7 @@
"4007": "Onduleur modifié !",
"4008": "Onduleur supprimé !",
"4009": "Inverter order saved!",
"5001": "@:apiresponse.2001",
"5001": "@:apiresponse.4001",
"5002": "La limite doit être comprise entre 1 et {max} !",
"5003": "Type spécifié invalide !",
"5004": "Onduleur spécifié invalide !",
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/views/InverterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<form class="form-inline" v-on:submit.prevent="onSubmit">
<div class="form-group">
<label>{{ $t('inverteradmin.Serial') }}</label>
<input v-model="newInverterData.serial" type="number" class="form-control ml-sm-2 mr-sm-4 my-2"
<input v-model="newInverterData.serial" type="text" class="form-control ml-sm-2 mr-sm-4 my-2"
required />
</div>
<div class="form-group">
Expand Down Expand Up @@ -91,7 +91,7 @@
<label for="inverter-serial" class="col-form-label">
{{ $t('inverteradmin.InverterSerial') }}
</label>
<input v-model="selectedInverterData.serial" type="number" id="inverter-serial" class="form-control" />
<input v-model="selectedInverterData.serial" type="text" id="inverter-serial" class="form-control" />
<label for="inverter-name" class="col-form-label">{{ $t('inverteradmin.InverterName') }}
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.InverterNameHint')" />
</label>
Expand Down

0 comments on commit 3d96405

Please sign in to comment.