Skip to content

Commit e61d704

Browse files
gskjoldclaude
andauthored
Round scaled config values instead of truncating on cast (#1256)
User-entered decimals are stored as scaled integers, but the cast from double to integer truncates. atof("0.0464") is 0.046399999999999996, so * 10000.0 yields 463.99999999999994 and the price modifier is stored as 463 instead of 464. 68866 of the 999999 possible four-decimal price modifier values are stored one unit too low this way. Switching from float to double in a733365 barely moved that count (68886 before, 68866 after); it only changed which values land just below the integer, and 0.0464 moved into the broken set. Round with lround() at every scaling site instead: price modifiers, meter multipliers, Wi-Fi power, Vcc offset/multiplier/boot limit and the day/month plot editor, both in the web form handler and in the config file parser. The config file parser also still used toFloat() for the Vcc values and the price modifier, so it kept the old truncation on backup restore. Reported in #1251 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent f746899 commit e61d704

2 files changed

Lines changed: 23 additions & 21 deletions

File tree

src/AmsToMqttBridge.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
#include <Arduino.h>
13+
#include <math.h>
1314

1415
#if defined(ESP8266)
1516
#include <ESP8266WiFi.h>
@@ -2172,16 +2173,16 @@ void configFileParse() {
21722173
fromHex(meter.authenticationKey, String(buf+23), 16);
21732174
} else if(strncmp_P(buf, PSTR("meterWattageMultiplier "), 23) == 0) {
21742175
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
2175-
meter.wattageMultiplier = String(buf+23).toDouble() * 1000;
2176+
meter.wattageMultiplier = lround(String(buf+23).toDouble() * 1000.0);
21762177
} else if(strncmp_P(buf, PSTR("meterVoltageMultiplier "), 23) == 0) {
21772178
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
2178-
meter.voltageMultiplier = String(buf+23).toDouble() * 1000;
2179+
meter.voltageMultiplier = lround(String(buf+23).toDouble() * 1000.0);
21792180
} else if(strncmp_P(buf, PSTR("meterAmperageMultiplier "), 24) == 0) {
21802181
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
2181-
meter.amperageMultiplier = String(buf+24).toDouble() * 1000;
2182+
meter.amperageMultiplier = lround(String(buf+24).toDouble() * 1000.0);
21822183
} else if(strncmp_P(buf, PSTR("meterAccumulatedMultiplier "), 27) == 0) {
21832184
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
2184-
meter.accumulatedMultiplier = String(buf+27).toDouble() * 1000;
2185+
meter.accumulatedMultiplier = lround(String(buf+27).toDouble() * 1000.0);
21852186
} else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) {
21862187
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
21872188
meter.rxPin = String(buf+11).toInt();
@@ -2220,13 +2221,13 @@ void configFileParse() {
22202221
gpio.vccPin = String(buf+11).toInt();
22212222
} else if(strncmp_P(buf, PSTR("gpioVccOffset "), 14) == 0) {
22222223
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
2223-
gpio.vccOffset = String(buf+14).toFloat() * 100;
2224+
gpio.vccOffset = lround(String(buf+14).toDouble() * 100.0);
22242225
} else if(strncmp_P(buf, PSTR("gpioVccMultiplier "), 18) == 0) {
22252226
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
2226-
gpio.vccMultiplier = String(buf+18).toFloat() * 1000;
2227+
gpio.vccMultiplier = lround(String(buf+18).toDouble() * 1000.0);
22272228
} else if(strncmp_P(buf, PSTR("gpioVccBootLimit "), 17) == 0) {
22282229
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
2229-
gpio.vccBootLimit = String(buf+17).toFloat() * 10;
2230+
gpio.vccBootLimit = lround(String(buf+17).toDouble() * 10.0);
22302231
} else if(strncmp_P(buf, PSTR("gpioVccResistorGnd "), 19) == 0) {
22312232
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
22322233
gpio.vccResistorGnd = String(buf+19).toInt();
@@ -2339,7 +2340,7 @@ void configFileParse() {
23392340
continue;
23402341
}
23412342

2342-
pc.value = getSplit(rest, 2).toFloat() * 10000;
2343+
pc.value = lround(getSplit(rest, 2).toDouble() * 10000.0);
23432344

23442345
String days = getSplit(rest, 3);
23452346
if(days.equals("all")) {

src/AmsWebServer.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include "AmsWebServer.h"
8+
#include <math.h>
89
#include "CustomDefaults.h"
910
#include "AmsWebHeaders.h"
1011
#include "FirmwareVersion.h"
@@ -1386,10 +1387,10 @@ void AmsWebServer::handleSave() {
13861387
memset(meterConfig.authenticationKey, 0, 16);
13871388
}
13881389

1389-
meterConfig.wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000.0;
1390-
meterConfig.voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000.0;
1391-
meterConfig.amperageMultiplier = server.arg(F("mma")).toDouble() * 1000.0;
1392-
meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000.0;
1390+
meterConfig.wattageMultiplier = lround(server.arg(F("mmw")).toDouble() * 1000.0);
1391+
meterConfig.voltageMultiplier = lround(server.arg(F("mmv")).toDouble() * 1000.0);
1392+
meterConfig.amperageMultiplier = lround(server.arg(F("mma")).toDouble() * 1000.0);
1393+
meterConfig.accumulatedMultiplier = lround(server.arg(F("mmc")).toDouble() * 1000.0);
13931394
config->setMeterConfig(meterConfig);
13941395
}
13951396

@@ -1405,7 +1406,7 @@ void AmsWebServer::handleSave() {
14051406
if(!psk.equals("***")) {
14061407
strcpy(network.psk, psk.c_str());
14071408
}
1408-
network.power = server.arg(F("ww")).toDouble() * 10.0;
1409+
network.power = lround(server.arg(F("ww")).toDouble() * 10.0);
14091410
network.sleep = server.arg(F("wz")).toInt();
14101411
network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true");
14111412
}
@@ -1567,9 +1568,9 @@ void AmsWebServer::handleSave() {
15671568
}
15681569

15691570
if(server.hasArg(F("iv")) && server.arg(F("iv")) == F("true")) {
1570-
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toDouble() * 100.0 : 0;
1571-
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toDouble() * 1000.0 : 1000;
1572-
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toDouble() * 10.0 : 0;
1571+
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? lround(server.arg(F("ivo")).toDouble() * 100.0) : 0;
1572+
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? lround(server.arg(F("ivm")).toDouble() * 1000.0) : 1000;
1573+
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? lround(server.arg(F("ivb")).toDouble() * 10.0) : 0;
15731574
config->setGpioConfig(*gpioConfig);
15741575
}
15751576

@@ -1684,7 +1685,7 @@ void AmsWebServer::handleSave() {
16841685
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("rd%d"), i);
16851686
pc.direction = server.arg(buf).toInt();
16861687
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("rv%d"), i);
1687-
pc.value = server.arg(buf).toDouble() * 10000.0;
1688+
pc.value = lround(server.arg(buf).toDouble() * 10000.0);
16881689
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("rn%d"), i);
16891690
String name = server.arg(buf);
16901691
strcpy(pc.name, name.c_str());
@@ -2773,11 +2774,11 @@ void AmsWebServer::modifyDayPlot() {
27732774
for(uint8_t i = 0; i < 24; i++) {
27742775
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("i%02d"), i);
27752776
if(server.hasArg(buf)) {
2776-
ds->setHourImport(i, server.arg(buf).toDouble() * 1000);
2777+
ds->setHourImport(i, lround(server.arg(buf).toDouble() * 1000.0));
27772778
}
27782779
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("e%02d"), i);
27792780
if(server.hasArg(buf)) {
2780-
ds->setHourExport(i, server.arg(buf).toDouble() * 1000);
2781+
ds->setHourExport(i, lround(server.arg(buf).toDouble() * 1000.0));
27812782
}
27822783
}
27832784
bool ret = ds->save();
@@ -2798,11 +2799,11 @@ void AmsWebServer::modifyMonthPlot() {
27982799
for(uint8_t i = 1; i <= 31; i++) {
27992800
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("i%02d"), i);
28002801
if(server.hasArg(buf)) {
2801-
ds->setDayImport(i, server.arg(buf).toDouble() * 1000);
2802+
ds->setDayImport(i, lround(server.arg(buf).toDouble() * 1000.0));
28022803
}
28032804
snprintf_P(buf, BUF_SIZE_COMMON, PSTR("e%02d"), i);
28042805
if(server.hasArg(buf)) {
2805-
ds->setDayExport(i, server.arg(buf).toDouble() * 1000);
2806+
ds->setDayExport(i, lround(server.arg(buf).toDouble() * 1000.0));
28062807
}
28072808
}
28082809
bool ret = ds->save();

0 commit comments

Comments
 (0)