mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-29 03:14:58 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fd383c1ef | ||
|
|
a931f4cef8 | ||
|
|
fddecaab39 | ||
|
|
e5eab82d68 | ||
|
|
8ae1d46b2a | ||
|
|
99ccb03b45 | ||
|
|
b8f2d501a5 | ||
|
|
e042806619 | ||
|
|
16f9ed7ecb | ||
|
|
3eaefefd26 | ||
|
|
03c8c3ddbc | ||
|
|
08371b9078 | ||
|
|
a6ae25f3e7 |
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -68,14 +68,11 @@ jobs:
|
|||||||
run: pio lib install
|
run: pio lib install
|
||||||
|
|
||||||
- name: Create release with release notes
|
- name: Create release with release notes
|
||||||
env:
|
id: create_release
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
uses: ncipollo/release-action@v1
|
||||||
tag: ${{ github.ref_name }}
|
with:
|
||||||
run: |
|
name: Release v${{ steps.release_tag.outputs.tag }}
|
||||||
gh release create "$tag" \
|
generateReleaseNotes: true
|
||||||
--repo="$GITHUB_REPOSITORY" \
|
|
||||||
--title="${tag#v}" \
|
|
||||||
--generate-notes
|
|
||||||
|
|
||||||
- name: Build esp8266 firmware
|
- name: Build esp8266 firmware
|
||||||
run: pio run -e esp8266
|
run: pio run -e esp8266
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ IEC6205621::IEC6205621(const char* p, Timezone* tz, MeterConfig* meterConfig) {
|
|||||||
if(strlen(p) < 16)
|
if(strlen(p) < 16)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this->packageTimestamp = time(nullptr);
|
||||||
|
|
||||||
String payload(p+1);
|
String payload(p+1);
|
||||||
|
|
||||||
lastUpdateMillis = millis64();
|
lastUpdateMillis = millis64();
|
||||||
@@ -59,15 +61,44 @@ IEC6205621::IEC6205621(const char* p, Timezone* tz, MeterConfig* meterConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmElements_t tm { 0, 0, 0, 0, 0, 0, 0 };
|
||||||
String timestamp = extract(payload, F("1.0.0"));
|
String timestamp = extract(payload, F("1.0.0"));
|
||||||
if(timestamp.length() > 10) {
|
if(timestamp.length() == 13) { // yyMMddHHmmssX
|
||||||
tmElements_t tm;
|
char x = timestamp.charAt(12);
|
||||||
|
if(x == 'S' || x == 'W') {
|
||||||
tm.Year = (timestamp.substring(0,2).toInt() + 2000) - 1970;
|
tm.Year = (timestamp.substring(0,2).toInt() + 2000) - 1970;
|
||||||
tm.Month = timestamp.substring(4,6).toInt();
|
tm.Month = timestamp.substring(2,4).toInt();
|
||||||
tm.Day = timestamp.substring(2,4).toInt();
|
tm.Day = timestamp.substring(4,6).toInt();
|
||||||
tm.Hour = timestamp.substring(6,8).toInt();
|
tm.Hour = timestamp.substring(6,8).toInt();
|
||||||
tm.Minute = timestamp.substring(8,10).toInt();
|
tm.Minute = timestamp.substring(8,10).toInt();
|
||||||
tm.Second = timestamp.substring(10,12).toInt();
|
tm.Second = timestamp.substring(10,12).toInt();
|
||||||
|
}
|
||||||
|
} else if(timestamp.length() == 17) { // yyyyMMdd HH:mm:ss
|
||||||
|
char x = timestamp.charAt(11);
|
||||||
|
char y = timestamp.charAt(14);
|
||||||
|
if(x == ':' && y == ':') {
|
||||||
|
tm.Year = (timestamp.substring(0,4).toInt()) - 1970;
|
||||||
|
tm.Month = timestamp.substring(4,6).toInt();
|
||||||
|
tm.Day = timestamp.substring(6,8).toInt();
|
||||||
|
tm.Hour = timestamp.substring(9,11).toInt();
|
||||||
|
tm.Minute = timestamp.substring(12,14).toInt();
|
||||||
|
tm.Second = timestamp.substring(15,17).toInt();
|
||||||
|
}
|
||||||
|
} else if(timestamp.length() == 19) { // yyyy-MM-dd HH:mm:ss
|
||||||
|
char x = timestamp.charAt(4);
|
||||||
|
char y = timestamp.charAt(13);
|
||||||
|
if(x == '-' && y == ':') {
|
||||||
|
tm.Year = (timestamp.substring(0,4).toInt()) - 1970;
|
||||||
|
tm.Month = timestamp.substring(5,7).toInt();
|
||||||
|
tm.Day = timestamp.substring(8,10).toInt();
|
||||||
|
tm.Hour = timestamp.substring(11,13).toInt();
|
||||||
|
tm.Minute = timestamp.substring(14,16).toInt();
|
||||||
|
tm.Second = timestamp.substring(17,19).toInt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
meterTimestamp = 0;
|
||||||
|
}
|
||||||
|
if(tm.Year > 0) {
|
||||||
meterTimestamp = makeTime(tm);
|
meterTimestamp = makeTime(tm);
|
||||||
if(tz != NULL) meterTimestamp = tz->toUTC(meterTimestamp);
|
if(tz != NULL) meterTimestamp = tz->toUTC(meterTimestamp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
|
|||||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||||
if(data->base.length == 0x12) {
|
if(data->base.length == 0x12) {
|
||||||
apply(state);
|
apply(state);
|
||||||
listType = state.getListType() > 2 ? state.getListType() : 2;
|
listType = state.getListType() > 4 ? state.getListType() : 4;
|
||||||
|
|
||||||
// 42.0.0 COSEM logical device name
|
// 42.0.0 COSEM logical device name
|
||||||
idx++;
|
idx++;
|
||||||
@@ -327,7 +327,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
|
|||||||
CosemData* no7 = getCosemDataAt(7, ((char *) (d)));
|
CosemData* no7 = getCosemDataAt(7, ((char *) (d)));
|
||||||
if(no7->base.type == CosemTypeLongUnsigned) {
|
if(no7->base.type == CosemTypeLongUnsigned) {
|
||||||
apply(state);
|
apply(state);
|
||||||
listType = state.getListType() > 2 ? state.getListType() : 2;
|
listType = state.getListType() > 4 ? state.getListType() : 4;
|
||||||
|
|
||||||
// 42.0.0 COSEM logical device name
|
// 42.0.0 COSEM logical device name
|
||||||
idx++;
|
idx++;
|
||||||
|
|||||||
@@ -42,33 +42,75 @@ LNG::LNG(AmsData& meterState, const char* payload, uint8_t useMeterType, MeterCo
|
|||||||
switch(descriptor->obis[2]) {
|
switch(descriptor->obis[2]) {
|
||||||
case 1:
|
case 1:
|
||||||
o170 = getNumber(item);
|
o170 = getNumber(item);
|
||||||
|
if(meterConfig->wattageMultiplier > 0) {
|
||||||
|
o170 = o170 > 0 ? o170 * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
o270 = getNumber(item);
|
o270 = getNumber(item);
|
||||||
|
if(meterConfig->wattageMultiplier > 0) {
|
||||||
|
o270 = o270 > 0 ? o270 * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
reactiveImportPower = getNumber(item);
|
reactiveImportPower = getNumber(item);
|
||||||
|
if(meterConfig->wattageMultiplier > 0) {
|
||||||
|
reactiveImportPower = reactiveImportPower > 0 ? reactiveImportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
reactiveExportPower = getNumber(item);
|
reactiveExportPower = getNumber(item);
|
||||||
|
if(meterConfig->wattageMultiplier > 0) {
|
||||||
|
reactiveExportPower = reactiveExportPower > 0 ? reactiveExportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
l1activeImportPower = getNumber(item);
|
||||||
|
listType = listType >= 4 ? listType : 4;
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
l2activeImportPower = getNumber(item);
|
||||||
|
listType = listType >= 4 ? listType : 4;
|
||||||
|
break;
|
||||||
|
case 61:
|
||||||
|
l3activeImportPower = getNumber(item);
|
||||||
|
listType = listType >= 4 ? listType : 4;
|
||||||
break;
|
break;
|
||||||
case 31:
|
case 31:
|
||||||
l1current = getNumber(item) / 100.0;
|
l1current = getNumber(item) / 100.0;
|
||||||
|
if(meterConfig->amperageMultiplier > 0) {
|
||||||
|
l1current = l1current > 0 ? l1current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 51:
|
case 51:
|
||||||
l2current = getNumber(item) / 100.0;
|
l2current = getNumber(item) / 100.0;
|
||||||
|
if(meterConfig->amperageMultiplier > 0) {
|
||||||
|
l2current = l2current > 0 ? l2current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 71:
|
case 71:
|
||||||
l3current = getNumber(item) / 100.0;
|
l3current = getNumber(item) / 100.0;
|
||||||
|
if(meterConfig->amperageMultiplier > 0) {
|
||||||
|
l3current = l3current > 0 ? l3current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
l1voltage = getNumber(item) / 10.0;
|
l1voltage = getNumber(item) / 10.0;
|
||||||
|
if(meterConfig->voltageMultiplier > 0) {
|
||||||
|
l1voltage = l1voltage > 0 ? l1voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 52:
|
case 52:
|
||||||
l2voltage = getNumber(item) / 10.0;
|
l2voltage = getNumber(item) / 10.0;
|
||||||
|
if(meterConfig->voltageMultiplier > 0) {
|
||||||
|
l2voltage = l2voltage > 0 ? l2voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 72:
|
case 72:
|
||||||
l3voltage = getNumber(item) / 10.0;
|
l3voltage = getNumber(item) / 10.0;
|
||||||
|
if(meterConfig->voltageMultiplier > 0) {
|
||||||
|
l3voltage = l3voltage > 0 ? l3voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,30 +121,54 @@ LNG::LNG(AmsData& meterState, const char* payload, uint8_t useMeterType, MeterCo
|
|||||||
case 1:
|
case 1:
|
||||||
o180 = getNumber(item);
|
o180 = getNumber(item);
|
||||||
activeImportCounter = o180 / 1000.0;
|
activeImportCounter = o180 / 1000.0;
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
activeImportCounter = activeImportCounter > 0 ? activeImportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
o280 = getNumber(item);
|
o280 = getNumber(item);
|
||||||
activeExportCounter = o280 / 1000.0;
|
activeExportCounter = o280 / 1000.0;
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
activeExportCounter = activeExportCounter > 0 ? activeExportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
o380 = getNumber(item);
|
o380 = getNumber(item);
|
||||||
reactiveImportCounter = o380 / 1000.0;
|
reactiveImportCounter = o380 / 1000.0;
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
reactiveImportCounter = reactiveImportCounter > 0 ? reactiveImportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
o480 = getNumber(item);
|
o480 = getNumber(item);
|
||||||
reactiveExportCounter = o480 / 1000.0;
|
reactiveExportCounter = o480 / 1000.0;
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
reactiveExportCounter = reactiveExportCounter > 0 ? reactiveExportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
o580 = getNumber(item);
|
o580 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o580 = o580 > 0 ? o580 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
o680 = getNumber(item);
|
o680 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o680 = o680 > 0 ? o680 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
o780 = getNumber(item);
|
o780 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o780 = o780 > 0 ? o780 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
o880 = getNumber(item);
|
o880 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o880 = o880 > 0 ? o880 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(descriptor->obis[4] == 1) {
|
} else if(descriptor->obis[4] == 1) {
|
||||||
@@ -110,9 +176,15 @@ LNG::LNG(AmsData& meterState, const char* payload, uint8_t useMeterType, MeterCo
|
|||||||
switch(descriptor->obis[2]) {
|
switch(descriptor->obis[2]) {
|
||||||
case 1:
|
case 1:
|
||||||
o181 = getNumber(item);
|
o181 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o181 = o181 > 0 ? o181 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
o281 = getNumber(item);
|
o281 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o281 = o281 > 0 ? o281 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(descriptor->obis[4] == 2) {
|
} else if(descriptor->obis[4] == 2) {
|
||||||
@@ -120,9 +192,15 @@ LNG::LNG(AmsData& meterState, const char* payload, uint8_t useMeterType, MeterCo
|
|||||||
switch(descriptor->obis[2]) {
|
switch(descriptor->obis[2]) {
|
||||||
case 1:
|
case 1:
|
||||||
o182 = getNumber(item);
|
o182 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o182 = o182 > 0 ? o182 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
o282 = getNumber(item);
|
o282 = getNumber(item);
|
||||||
|
if(meterConfig->accumulatedMultiplier > 0) {
|
||||||
|
o282 = o282 > 0 ? o282 * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,28 +261,6 @@ LNG::LNG(AmsData& meterState, const char* payload, uint8_t useMeterType, MeterCo
|
|||||||
lastUpdateMillis = millis64();
|
lastUpdateMillis = millis64();
|
||||||
}
|
}
|
||||||
lastUpdateMillis = millis64();
|
lastUpdateMillis = millis64();
|
||||||
if(meterConfig->wattageMultiplier > 0) {
|
|
||||||
activeImportPower = activeImportPower > 0 ? activeImportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
|
||||||
activeExportPower = activeExportPower > 0 ? activeExportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
|
||||||
reactiveImportPower = reactiveImportPower > 0 ? reactiveImportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
|
||||||
reactiveExportPower = reactiveExportPower > 0 ? reactiveExportPower * (meterConfig->wattageMultiplier / 1000.0) : 0;
|
|
||||||
}
|
|
||||||
if(meterConfig->voltageMultiplier > 0) {
|
|
||||||
l1voltage = l1voltage > 0 ? l1voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
|
||||||
l2voltage = l2voltage > 0 ? l2voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
|
||||||
l3voltage = l3voltage > 0 ? l3voltage * (meterConfig->voltageMultiplier / 1000.0) : 0;
|
|
||||||
}
|
|
||||||
if(meterConfig->amperageMultiplier > 0) {
|
|
||||||
l1current = l1current > 0 ? l1current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
|
||||||
l2current = l2current > 0 ? l2current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
|
||||||
l3current = l3current > 0 ? l3current * (meterConfig->amperageMultiplier / 1000.0) : 0;
|
|
||||||
}
|
|
||||||
if(meterConfig->accumulatedMultiplier > 0) {
|
|
||||||
activeImportCounter = activeImportCounter > 0 ? activeImportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
|
||||||
activeExportCounter = activeExportCounter > 0 ? activeExportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
|
||||||
reactiveImportCounter = reactiveImportCounter > 0 ? reactiveImportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
|
||||||
reactiveExportCounter = reactiveExportCounter > 0 ? reactiveExportCounter * (meterConfig->accumulatedMultiplier / 1000.0) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
threePhase = l1voltage > 0 && l2voltage > 0 && l3voltage > 0;
|
threePhase = l1voltage > 0 && l2voltage > 0 && l3voltage > 0;
|
||||||
if(!threePhase)
|
if(!threePhase)
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public:
|
|||||||
PriceService(Stream*);
|
PriceService(Stream*);
|
||||||
#endif
|
#endif
|
||||||
void setup(PriceServiceConfig&);
|
void setup(PriceServiceConfig&);
|
||||||
|
void setTimezone(Timezone* tz);
|
||||||
bool loop();
|
bool loop();
|
||||||
|
|
||||||
char* getToken();
|
char* getToken();
|
||||||
@@ -114,6 +115,7 @@ private:
|
|||||||
std::vector<PriceConfig> priceConfig;
|
std::vector<PriceConfig> priceConfig;
|
||||||
|
|
||||||
Timezone* tz = NULL;
|
Timezone* tz = NULL;
|
||||||
|
Timezone* entsoeTz = NULL;
|
||||||
|
|
||||||
static const uint16_t BufferSize = 256;
|
static const uint16_t BufferSize = 256;
|
||||||
char* buf;
|
char* buf;
|
||||||
@@ -129,5 +131,6 @@ private:
|
|||||||
PricesContainer* fetchPrices(time_t);
|
PricesContainer* fetchPrices(time_t);
|
||||||
bool retrieve(const char* url, Stream* doc);
|
bool retrieve(const char* url, Stream* doc);
|
||||||
float getCurrencyMultiplier(const char* from, const char* to, time_t t);
|
float getCurrencyMultiplier(const char* from, const char* to, time_t t);
|
||||||
|
bool timeIsInPeriod(tmElements_t tm, PriceConfig pc);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ PriceService::PriceService(Stream* Debug) : priceConfig(std::vector<PriceConfig>
|
|||||||
// Entso-E uses CET/CEST
|
// Entso-E uses CET/CEST
|
||||||
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};
|
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};
|
||||||
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};
|
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};
|
||||||
tz = new Timezone(CEST, CET);
|
entsoeTz = new Timezone(CEST, CET);
|
||||||
|
tz = entsoeTz;
|
||||||
|
|
||||||
tomorrowFetchMinute = 15 + random(45); // Random between 13:15 and 14:00
|
tomorrowFetchMinute = 15 + random(45); // Random between 13:15 and 14:00
|
||||||
}
|
}
|
||||||
@@ -72,6 +73,10 @@ void PriceService::setup(PriceServiceConfig& config) {
|
|||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PriceService::setTimezone(Timezone* tz) {
|
||||||
|
this->tz = tz;
|
||||||
|
}
|
||||||
|
|
||||||
char* PriceService::getToken() {
|
char* PriceService::getToken() {
|
||||||
return this->config->entsoeToken;
|
return this->config->entsoeToken;
|
||||||
}
|
}
|
||||||
@@ -111,18 +116,12 @@ float PriceService::getValueForHour(uint8_t direction, time_t ts, int8_t hour) {
|
|||||||
|
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime(tz->toLocal(ts + (hour * SECS_PER_HOUR)), tm);
|
breakTime(tz->toLocal(ts + (hour * SECS_PER_HOUR)), tm);
|
||||||
uint8_t day = 0x01 << ((tm.Wday+5)%7);
|
|
||||||
uint32_t hrs = 0x01 << tm.Hour;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
||||||
PriceConfig pc = priceConfig.at(i);
|
PriceConfig pc = priceConfig.at(i);
|
||||||
if(pc.type == PRICE_TYPE_FIXED) continue;
|
if(pc.type == PRICE_TYPE_FIXED) continue;
|
||||||
uint8_t start_month = pc.start_month == 0 || pc.start_month > 12 ? 1 : pc.start_month;
|
if((pc.direction & direction) != direction) continue;
|
||||||
uint8_t start_dayofmonth = pc.start_dayofmonth == 0 || pc.start_dayofmonth > 31 ? 1 : pc.start_dayofmonth;
|
if(!timeIsInPeriod(tm, pc)) continue;
|
||||||
uint8_t end_month = pc.end_month == 0 || pc.end_month > 12 ? 12 : pc.end_month;
|
|
||||||
uint8_t end_dayofmonth = pc.end_dayofmonth == 0 || pc.end_dayofmonth > 31 ? 31 : pc.end_dayofmonth;
|
|
||||||
|
|
||||||
if((pc.direction & direction) == direction && (pc.days & day) == day && (pc.hours & hrs) == hrs && tm.Month >= start_month && tm.Day >= start_dayofmonth && tm.Month <= end_month && tm.Day <= end_dayofmonth) {
|
|
||||||
switch(pc.type) {
|
switch(pc.type) {
|
||||||
case PRICE_TYPE_ADD:
|
case PRICE_TYPE_ADD:
|
||||||
ret += pc.value / 10000.0;
|
ret += pc.value / 10000.0;
|
||||||
@@ -135,55 +134,48 @@ float PriceService::getValueForHour(uint8_t direction, time_t ts, int8_t hour) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PriceService::getEnergyPriceForHour(uint8_t direction, time_t ts, int8_t hour) {
|
float PriceService::getEnergyPriceForHour(uint8_t direction, time_t ts, int8_t hour) {
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime(tz->toLocal(ts + (hour * SECS_PER_HOUR)), tm);
|
breakTime(tz->toLocal(ts + (hour * SECS_PER_HOUR)), tm);
|
||||||
uint8_t day = 0x01 << ((tm.Wday+5)%7);
|
|
||||||
uint32_t hrs = 0x01 << tm.Hour;
|
|
||||||
|
|
||||||
float value = PRICE_NO_VALUE;
|
float value = PRICE_NO_VALUE;
|
||||||
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
||||||
PriceConfig pc = priceConfig.at(i);
|
PriceConfig pc = priceConfig.at(i);
|
||||||
if(pc.type != PRICE_TYPE_FIXED) continue;
|
if(pc.type != PRICE_TYPE_FIXED) continue;
|
||||||
uint8_t start_month = pc.start_month == 0 || pc.start_month > 12 ? 1 : pc.start_month;
|
if((pc.direction & direction) != direction) continue;
|
||||||
uint8_t start_dayofmonth = pc.start_dayofmonth == 0 || pc.start_dayofmonth > 31 ? 1 : pc.start_dayofmonth;
|
if(!timeIsInPeriod(tm, pc)) continue;
|
||||||
uint8_t end_month = pc.end_month == 0 || pc.end_month > 12 ? 12 : pc.end_month;
|
|
||||||
uint8_t end_dayofmonth = pc.end_dayofmonth == 0 || pc.end_dayofmonth > 31 ? 31 : pc.end_dayofmonth;
|
|
||||||
|
|
||||||
if((pc.direction & direction) == direction && (pc.days & day) == day && (pc.hours & hrs) == hrs && tm.Month >= start_month && tm.Day >= start_dayofmonth && tm.Month <= end_month && tm.Day <= end_dayofmonth) {
|
|
||||||
if(value == PRICE_NO_VALUE) {
|
if(value == PRICE_NO_VALUE) {
|
||||||
value = pc.value / 10000.0;
|
value = pc.value / 10000.0;
|
||||||
} else {
|
} else {
|
||||||
value += pc.value / 10000.0;
|
value += pc.value / 10000.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(value != PRICE_NO_VALUE) return value;
|
if(value != PRICE_NO_VALUE) return value;
|
||||||
|
|
||||||
int8_t pos = hour;
|
int8_t pos = hour;
|
||||||
|
|
||||||
breakTime(tz->toLocal(ts), tm);
|
breakTime(entsoeTz->toLocal(ts), tm);
|
||||||
while(tm.Hour > 0) {
|
while(tm.Hour > 0) {
|
||||||
ts -= 3600;
|
ts -= 3600;
|
||||||
breakTime(tz->toLocal(ts), tm);
|
breakTime(entsoeTz->toLocal(ts), tm);
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
uint8_t hoursToday = 0;
|
uint8_t hoursToday = 0;
|
||||||
uint8_t todayDate = tm.Day;
|
uint8_t todayDate = tm.Day;
|
||||||
while(tm.Day == todayDate) {
|
while(tm.Day == todayDate) {
|
||||||
ts += 3600;
|
ts += 3600;
|
||||||
breakTime(tz->toLocal(ts), tm);
|
breakTime(entsoeTz->toLocal(ts), tm);
|
||||||
hoursToday++;
|
hoursToday++;
|
||||||
}
|
}
|
||||||
uint8_t hoursTomorrow = 0;
|
uint8_t hoursTomorrow = 0;
|
||||||
uint8_t tomorrowDate = tm.Day;
|
uint8_t tomorrowDate = tm.Day;
|
||||||
while(tm.Day == tomorrowDate) {
|
while(tm.Day == tomorrowDate) {
|
||||||
ts += 3600;
|
ts += 3600;
|
||||||
breakTime(tz->toLocal(ts), tm);
|
breakTime(entsoeTz->toLocal(ts), tm);
|
||||||
hoursTomorrow++;
|
hoursTomorrow++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +236,7 @@ bool PriceService::loop() {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime(tz->toLocal(t), tm);
|
breakTime(entsoeTz->toLocal(t), tm);
|
||||||
|
|
||||||
if(currentDay == 0) {
|
if(currentDay == 0) {
|
||||||
currentDay = tm.Day;
|
currentDay = tm.Day;
|
||||||
@@ -415,7 +407,7 @@ float PriceService::getCurrencyMultiplier(const char* from, const char* to, time
|
|||||||
PricesContainer* PriceService::fetchPrices(time_t t) {
|
PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||||
if(strlen(getToken()) > 0) {
|
if(strlen(getToken()) > 0) {
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime(tz->toLocal(t), tm);
|
breakTime(entsoeTz->toLocal(t), tm);
|
||||||
time_t e1 = t - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; // Local midnight
|
time_t e1 = t - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; // Local midnight
|
||||||
time_t e2 = e1 + SECS_PER_DAY;
|
time_t e2 = e1 + SECS_PER_DAY;
|
||||||
tmElements_t d1, d2;
|
tmElements_t d1, d2;
|
||||||
@@ -452,7 +444,7 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
|||||||
}
|
}
|
||||||
} else if(hub) {
|
} else if(hub) {
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime(tz->toLocal(t), tm);
|
breakTime(entsoeTz->toLocal(t), tm);
|
||||||
|
|
||||||
String data;
|
String data;
|
||||||
snprintf_P(buf, BufferSize, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d?currency=%s"),
|
snprintf_P(buf, BufferSize, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d?currency=%s"),
|
||||||
@@ -633,3 +625,37 @@ bool PriceService::load() {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PriceService::timeIsInPeriod(tmElements_t tm, PriceConfig pc) {
|
||||||
|
uint8_t day = 0x01 << ((tm.Wday+5)%7);
|
||||||
|
uint32_t hrs = 0x01 << tm.Hour;
|
||||||
|
|
||||||
|
if((pc.days & day) != day) return false;
|
||||||
|
if((pc.hours & hrs) != hrs) return false;
|
||||||
|
|
||||||
|
tmElements_t tms;
|
||||||
|
tms.Year = tm.Year;
|
||||||
|
tms.Month = pc.start_month;
|
||||||
|
tms.Day = pc.start_dayofmonth;
|
||||||
|
tms.Hour = 0;
|
||||||
|
tms.Minute = 0;
|
||||||
|
tms.Second = 0;
|
||||||
|
|
||||||
|
tmElements_t tme;
|
||||||
|
tme.Year = tm.Year;
|
||||||
|
tme.Month = pc.end_month;
|
||||||
|
tme.Day = pc.end_dayofmonth;
|
||||||
|
tme.Hour = 23;
|
||||||
|
tme.Minute = 59;
|
||||||
|
tme.Second = 59;
|
||||||
|
if(makeTime(tms) > makeTime(tme)) {
|
||||||
|
if(makeTime(tm) <= makeTime(tme)) {
|
||||||
|
tms.Year--;
|
||||||
|
} else {
|
||||||
|
tme.Year++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeTime(tms) <= makeTime(tm) && makeTime(tme) >= makeTime(tm);
|
||||||
|
}
|
||||||
18
lib/SvelteUi/app/package-lock.json
generated
18
lib/SvelteUi/app/package-lock.json
generated
@@ -15,7 +15,7 @@
|
|||||||
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.9",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"svelte": "^4.2.19",
|
"svelte": "^4.2.19",
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"svelte-preprocess": "^5.0.3",
|
"svelte-preprocess": "^5.0.3",
|
||||||
"svelte-qrcode": "^1.0.0",
|
"svelte-qrcode": "^1.0.0",
|
||||||
"tailwindcss": "^3.3.1",
|
"tailwindcss": "^3.3.1",
|
||||||
"vite": "^4.5.9"
|
"vite": "^4.5.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@@ -1543,10 +1543,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http-proxy-middleware": {
|
"node_modules/http-proxy-middleware": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
|
||||||
"integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==",
|
"integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-proxy": "^1.17.8",
|
"@types/http-proxy": "^1.17.8",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
@@ -3359,10 +3360,11 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.5.9",
|
"version": "4.5.14",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz",
|
||||||
"integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==",
|
"integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.27",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.9",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"svelte": "^4.2.19",
|
"svelte": "^4.2.19",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"svelte-preprocess": "^5.0.3",
|
"svelte-preprocess": "^5.0.3",
|
||||||
"svelte-qrcode": "^1.0.0",
|
"svelte-qrcode": "^1.0.0",
|
||||||
"tailwindcss": "^3.3.1",
|
"tailwindcss": "^3.3.1",
|
||||||
"vite": "^4.5.9"
|
"vite": "^4.5.14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano": "^5.1.15",
|
"cssnano": "^5.1.15",
|
||||||
|
|||||||
@@ -680,7 +680,7 @@ void AmsWebServer::dayplotJson() {
|
|||||||
} else {
|
} else {
|
||||||
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
|
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
|
||||||
for(uint8_t i = 0; i < 24; i++) {
|
for(uint8_t i = 0; i < 24; i++) {
|
||||||
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.2f,\"e%02d\":%.2f"), i, ds->getHourImport(i) / 1000.0, i, ds->getHourExport(i) / 1000.0);
|
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getHourImport(i) / 1000.0, i, ds->getHourExport(i) / 1000.0);
|
||||||
}
|
}
|
||||||
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
|
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
|
||||||
|
|
||||||
@@ -703,7 +703,7 @@ void AmsWebServer::monthplotJson() {
|
|||||||
} else {
|
} else {
|
||||||
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
|
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
|
||||||
for(uint8_t i = 1; i < 32; i++) {
|
for(uint8_t i = 1; i < 32; i++) {
|
||||||
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.2f,\"e%02d\":%.2f"), i, ds->getDayImport(i) / 1000.0, i, ds->getDayExport(i) / 1000.0);
|
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getDayImport(i) / 1000.0, i, ds->getDayExport(i) / 1000.0);
|
||||||
}
|
}
|
||||||
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
|
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
|
||||||
|
|
||||||
@@ -2283,6 +2283,14 @@ void AmsWebServer::configFileDownload() {
|
|||||||
if(meter.encryptionKey[0] != 0x00) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterEncryptionKey %s\n"), toHex(meter.encryptionKey, 16).c_str()));
|
if(meter.encryptionKey[0] != 0x00) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterEncryptionKey %s\n"), toHex(meter.encryptionKey, 16).c_str()));
|
||||||
if(meter.authenticationKey[0] != 0x00) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterAuthenticationKey %s\n"), toHex(meter.authenticationKey, 16).c_str()));
|
if(meter.authenticationKey[0] != 0x00) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterAuthenticationKey %s\n"), toHex(meter.authenticationKey, 16).c_str()));
|
||||||
}
|
}
|
||||||
|
if(meter.wattageMultiplier != 1.0 && meter.wattageMultiplier != 0.0)
|
||||||
|
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterWattageMultiplier %.3f\n"), meter.wattageMultiplier / 1000.0));
|
||||||
|
if(meter.voltageMultiplier != 1.0 && meter.voltageMultiplier != 0.0)
|
||||||
|
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterVoltageMultiplier %.3f\n"), meter.voltageMultiplier / 1000.0));
|
||||||
|
if(meter.amperageMultiplier != 1.0 && meter.amperageMultiplier != 0.0)
|
||||||
|
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterAmperageMultiplier %.3f\n"), meter.amperageMultiplier / 1000.0));
|
||||||
|
if(meter.accumulatedMultiplier != 1.0 && meter.accumulatedMultiplier != 0.0)
|
||||||
|
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("meterAccumulatedMultiplier %.3f\n"), meter.accumulatedMultiplier / 1000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(includeGpio) {
|
if(includeGpio) {
|
||||||
|
|||||||
@@ -977,6 +977,7 @@ void handleNtpChange() {
|
|||||||
ws.setTimezone(tz);
|
ws.setTimezone(tz);
|
||||||
ds.setTimezone(tz);
|
ds.setTimezone(tz);
|
||||||
ea.setTimezone(tz);
|
ea.setTimezone(tz);
|
||||||
|
ps->setTimezone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ackNtpChange();
|
config.ackNtpChange();
|
||||||
@@ -1718,6 +1719,18 @@ void configFileParse() {
|
|||||||
} else if(strncmp_P(buf, PSTR("meterAuthenticationKey "), 23) == 0) {
|
} else if(strncmp_P(buf, PSTR("meterAuthenticationKey "), 23) == 0) {
|
||||||
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
fromHex(meter.authenticationKey, String(buf+23), 16);
|
fromHex(meter.authenticationKey, String(buf+23), 16);
|
||||||
|
} else if(strncmp_P(buf, PSTR("meterWattageMultiplier "), 23) == 0) {
|
||||||
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
|
meter.wattageMultiplier = String(buf+23).toDouble() * 1000;
|
||||||
|
} else if(strncmp_P(buf, PSTR("meterVoltageMultiplier "), 23) == 0) {
|
||||||
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
|
meter.voltageMultiplier = String(buf+23).toDouble() * 1000;
|
||||||
|
} else if(strncmp_P(buf, PSTR("meterAmperageMultiplier "), 24) == 0) {
|
||||||
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
|
meter.amperageMultiplier = String(buf+24).toDouble() * 1000;
|
||||||
|
} else if(strncmp_P(buf, PSTR("meterAccumulatedMultiplier "), 27) == 0) {
|
||||||
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
|
meter.accumulatedMultiplier = String(buf+27).toDouble() * 1000;
|
||||||
} else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) {
|
} else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) {
|
||||||
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||||
meter.rxPin = String(buf+11).toInt();
|
meter.rxPin = String(buf+11).toInt();
|
||||||
|
|||||||
Reference in New Issue
Block a user