mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-12 21:44:21 +00:00
Compare commits
21 Commits
v2.5.1
...
feat/uniq_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60d9e1fd22 | ||
|
|
4698442101 | ||
|
|
0b4884652f | ||
|
|
82aeae8699 | ||
|
|
a7333653b0 | ||
|
|
24e63d5e32 | ||
|
|
eb7c266378 | ||
|
|
cf8c48ab99 | ||
|
|
78a1cd78ea | ||
|
|
fdfa6c1b52 | ||
|
|
4f1790a464 | ||
|
|
ca4cef5233 | ||
|
|
a0d7fd0d95 | ||
|
|
489dbf9254 | ||
|
|
a81aa11558 | ||
|
|
2e4a0fc0a3 | ||
|
|
fc6e9e8085 | ||
|
|
ad73821f1c | ||
|
|
98bf5b958f | ||
|
|
f323c5a4f6 | ||
|
|
ea91248e67 |
48
frames/iskra_croatia.txt
Normal file
48
frames/iskra_croatia.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
They actually use multiple frames, so this is a "fake" frame combining the two into one, but without checksum fields.
|
||||
|
||||
7E
|
||||
A0 BD
|
||||
CF 02 23 03 00 00
|
||||
E6 E7 00
|
||||
0F 00 03 46 3B
|
||||
0C 07 E9 0C 13 05 17 37 28 00 FF C4 00
|
||||
|
||||
02 21
|
||||
09 08 39 32 30 32 39 36 39 31
|
||||
09 04 17 37 28 00
|
||||
09 05 07 E9 0C 13 05
|
||||
06 00 6C 28 5A
|
||||
06 00 4B 76 1A
|
||||
06 00 20 B2 40
|
||||
06 00 58 68 AA
|
||||
06 00 57 A1 62
|
||||
06 00 00 C7 48
|
||||
06 00 17 EE D7
|
||||
06 00 12 F5 5C
|
||||
06 00 00 D9 6A
|
||||
06 00 15 36 84
|
||||
06 00 00 01 7E
|
||||
06 00 00 00 00
|
||||
12 03 79
|
||||
06 00 00 00 7F
|
||||
06 00 00 00 BD
|
||||
06 00 00 00 41
|
||||
06 00 00 00 00
|
||||
06 00 00 00 00
|
||||
06 00 00 00 00
|
||||
12 09 54
|
||||
12 09 35
|
||||
12 09 49
|
||||
12 00 37
|
||||
12 00 59
|
||||
12 00 4D
|
||||
06 00 00 43 62
|
||||
01 01
|
||||
12 24 B8
|
||||
01 01
|
||||
12 24 B8
|
||||
01 01
|
||||
12 24 B8
|
||||
03 01
|
||||
|
||||
00 00 7E
|
||||
@@ -381,6 +381,8 @@ public:
|
||||
bool isZmartChargeConfigChanged();
|
||||
void ackZmartChargeConfig();
|
||||
|
||||
uint32_t getChipId();
|
||||
void getUniqueName(char* buffer, size_t length);
|
||||
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -124,16 +124,12 @@ void AmsConfiguration::clearNetworkConfig(NetworkConfig& config) {
|
||||
memset(config.ssid, 0, 32);
|
||||
memset(config.psk, 0, 64);
|
||||
clearNetworkConfigIp(config);
|
||||
|
||||
uint16_t chipId;
|
||||
getUniqueName(config.hostname, 32);
|
||||
#if defined(ESP32)
|
||||
chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF;
|
||||
config.power = 195;
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
config.power = 205;
|
||||
#endif
|
||||
strcpy(config.hostname, (String("ams-") + String(chipId, HEX)).c_str());
|
||||
config.mdns = true;
|
||||
config.sleep = 0xFF;
|
||||
config.use11b = 1;
|
||||
@@ -591,7 +587,6 @@ void AmsConfiguration::clearGpio(GpioConfig& config, bool all) {
|
||||
config.tempAnalogSensorPin = 0xFF;
|
||||
config.vccPin = 0xFF;
|
||||
config.ledDisablePin = 0xFF;
|
||||
config.powersaving = 0;
|
||||
|
||||
if(all) {
|
||||
config.vccOffset = 0;
|
||||
@@ -600,6 +595,7 @@ void AmsConfiguration::clearGpio(GpioConfig& config, bool all) {
|
||||
config.vccResistorGnd = 0;
|
||||
config.vccResistorVcc = 0;
|
||||
config.ledBehaviour = LED_BEHAVIOUR_DEFAULT;
|
||||
config.powersaving = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,6 +979,23 @@ void AmsConfiguration::setUiLanguageChanged() {
|
||||
uiLanguageChanged = true;
|
||||
}
|
||||
|
||||
uint32_t AmsConfiguration::getChipId() {
|
||||
uint32_t chipId;
|
||||
#if defined(ESP32)
|
||||
for(int i=0; i<17; i=i+8) {
|
||||
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
|
||||
}
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
return chipId;
|
||||
}
|
||||
|
||||
void AmsConfiguration::getUniqueName(char* buffer, size_t length) {
|
||||
uint32_t chipId = getChipId();
|
||||
snprintf(buffer, length, "ams-%06x", chipId);
|
||||
}
|
||||
|
||||
void AmsConfiguration::clear() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified, Pr
|
||||
fromHex((uint8_t*) &crc, String((char*) buf+crcPos), 2);
|
||||
crc = ntohs(crc);
|
||||
|
||||
if(crc != crc_calc) {
|
||||
if(crc > 0 && crc != crc_calc) {
|
||||
if(debugger != NULL) {
|
||||
debugger->printf_P(PSTR("CRC incorrrect, %04X != %04X at position %lu\n"), crc, crc_calc, crcPos);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
return DATA_PARSE_BOUNDARY_FLAG_MISSING;
|
||||
|
||||
// Verify FCS
|
||||
if(ntohs(f->fcs) != crc16_x25(d + 1, len - sizeof *f - 1))
|
||||
if(f->fcs > 0 && ntohs(f->fcs) != crc16_x25(d + 1, len - sizeof *f - 1))
|
||||
return DATA_PARSE_FOOTER_CHECKSUM_ERROR;
|
||||
|
||||
// Skip destination address, LSB marks last byte
|
||||
@@ -50,7 +50,7 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
HDLC3CtrlHcs* t3 = (HDLC3CtrlHcs*) (ptr);
|
||||
|
||||
// Verify HCS
|
||||
if(ntohs(t3->hcs) != crc16_x25(d + 1, ptr-d))
|
||||
if(t3->hcs > 0 && ntohs(t3->hcs) != crc16_x25(d + 1, ptr-d))
|
||||
return DATA_PARSE_HEADER_CHECKSUM_ERROR;
|
||||
ptr += 3;
|
||||
|
||||
@@ -69,7 +69,12 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
|
||||
if(buf == NULL) return DATA_PARSE_FAIL;
|
||||
|
||||
memcpy(buf + pos, ptr+3, ctx.length); // +3 to skip LLC
|
||||
if((*ptr) == DATA_TAG_LLC) {
|
||||
ptr += 3; // Skip LLC
|
||||
ctx.length -= 3;
|
||||
}
|
||||
|
||||
memcpy(buf + pos, ptr, ctx.length);
|
||||
pos += ctx.length;
|
||||
|
||||
lastSequenceNumber++;
|
||||
@@ -78,7 +83,12 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
lastSequenceNumber = 0;
|
||||
if(buf == NULL) return DATA_PARSE_FAIL;
|
||||
|
||||
memcpy(buf + pos, ptr+3, ctx.length); // +3 to skip LLC
|
||||
if((*ptr) == DATA_TAG_LLC) {
|
||||
ptr += 3; // Skip LLC
|
||||
ctx.length -= 3;
|
||||
}
|
||||
|
||||
memcpy(buf + pos, ptr, ctx.length);
|
||||
pos += ctx.length;
|
||||
|
||||
memcpy((uint8_t *) d, buf, pos);
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#define AMS_UPDATE_ERR_SUCCESS_CONFIRMED 123
|
||||
|
||||
#define UPDATE_BUF_SIZE 4096
|
||||
#define UPDATE_MAX_BLOCK_RETRY 25
|
||||
#define UPDATE_MAX_REBOOT_RETRY 12
|
||||
|
||||
class AmsFirmwareUpdater {
|
||||
public:
|
||||
|
||||
@@ -74,7 +74,7 @@ void AmsFirmwareUpdater::setUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
#endif
|
||||
debugger->printf_P(PSTR("Resuming uprade to %s\n"), updateStatus.toVersion);
|
||||
|
||||
if(updateStatus.reboot_count++ < 8) {
|
||||
if(updateStatus.reboot_count++ < UPDATE_MAX_REBOOT_RETRY) {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_OK;
|
||||
} else {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_REBOOT;
|
||||
@@ -129,7 +129,7 @@ void AmsFirmwareUpdater::loop() {
|
||||
HTTPClient http;
|
||||
start = millis();
|
||||
if(!fetchFirmwareChunk(http)) {
|
||||
if(updateStatus.retry_count++ == 3) {
|
||||
if(updateStatus.retry_count++ > UPDATE_MAX_BLOCK_RETRY) {
|
||||
updateStatus.errorCode = AMS_UPDATE_ERR_FETCH;
|
||||
updateStatusChanged = true;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
AmsMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, AmsFirmwareUpdater* updater) {
|
||||
#else
|
||||
AmsMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf) {
|
||||
AmsMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, AmsFirmwareUpdater* updater) {
|
||||
#endif
|
||||
this->mqttConfig = mqttConfig;
|
||||
this->mqttConfigChanged = true;
|
||||
|
||||
@@ -102,10 +102,17 @@ bool AmsMqttHandler::connect() {
|
||||
}
|
||||
actualClient = mqttClient;
|
||||
}
|
||||
int clientTimeout = mqttConfig.timeout / 1000;
|
||||
if(clientTimeout > 3) clientTimeout = 3; // 3000ms is default, see WiFiClient.cpp WIFI_CLIENT_DEF_CONN_TIMEOUT_MS
|
||||
actualClient->setTimeout(clientTimeout);
|
||||
// Why can't we set number of retries for write here? WiFiClient defaults to 10 (10*3s == 30s)
|
||||
|
||||
// This section helps with power saving on ESP32 devices by reducing timeouts
|
||||
// The timeout is multiplied by 10 because WiFiClient is retrying 10 times internally
|
||||
// Power drain for this timeout is too great when using the default 3s timeout
|
||||
// On ESP8266 the timeout is used differently and the following code causes MQTT instability
|
||||
#if defined(ESP32)
|
||||
int clientTimeout = mqttConfig.timeout / 1000;
|
||||
if(clientTimeout > 3) clientTimeout = 3; // 3000ms is default, see WiFiClient.cpp WIFI_CLIENT_DEF_CONN_TIMEOUT_MS
|
||||
actualClient->setTimeout(clientTimeout);
|
||||
// Why can't we set number of retries for write here? WiFiClient defaults to 10 (10*3s == 30s)
|
||||
#endif
|
||||
|
||||
mqttConfigChanged = false;
|
||||
mqtt.setTimeout(mqttConfig.timeout);
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
this->config = config;
|
||||
};
|
||||
#else
|
||||
DomoticzMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, DomoticzConfig config) : AmsMqttHandler(mqttConfig, debugger, buf) {
|
||||
DomoticzMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, DomoticzConfig config, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
|
||||
this->config = config;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -260,7 +260,9 @@ float EnergyAccounting::getUseThisMonth() {
|
||||
}
|
||||
|
||||
float EnergyAccounting::getUseLastMonth() {
|
||||
return (data.lastMonthImport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
float ret = (data.lastMonthImport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
if(std::isnan(ret)) return 0.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getProducedThisHour() {
|
||||
@@ -292,7 +294,9 @@ float EnergyAccounting::getProducedThisMonth() {
|
||||
}
|
||||
|
||||
float EnergyAccounting::getProducedLastMonth() {
|
||||
return (data.lastMonthExport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
float ret = (data.lastMonthExport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
if(std::isnan(ret)) return 0.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getCostThisHour() {
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
HomeAssistantMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, uint8_t boardType, HomeAssistantConfig config, HwTools* hw, AmsFirmwareUpdater* updater, char* hostname) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
|
||||
#else
|
||||
HomeAssistantMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, uint8_t boardType, HomeAssistantConfig config, HwTools* hw) : AmsMqttHandler(mqttConfig, debugger, buf) {
|
||||
HomeAssistantMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, uint8_t boardType, HomeAssistantConfig config, HwTools* hw, AmsFirmwareUpdater* updater, char* hostname) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
|
||||
#endif
|
||||
this->boardType = boardType;
|
||||
this->hw = hw;
|
||||
@@ -79,6 +79,7 @@ private:
|
||||
void publishPriceSensors(PriceService* ps);
|
||||
void publishSystemSensors();
|
||||
void publishThresholdSensors();
|
||||
void toJsonIsoTimestamp(time_t t, char* buf, size_t buflen);
|
||||
|
||||
String boardTypeToString(uint8_t b) {
|
||||
switch(b) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"P" : %lu,
|
||||
"t" : "%s"
|
||||
"t" : %s
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
"tPO" : %.3f,
|
||||
"tQI" : %.3f,
|
||||
"tQO" : %.3f,
|
||||
"rtc" : "%s",
|
||||
"t" : "%s"
|
||||
"rtc" : %s,
|
||||
"t" : %s
|
||||
}
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"U1" : %.2f,
|
||||
"U2" : %.2f,
|
||||
"U3" : %.2f,
|
||||
"t" : "%s"
|
||||
"t" : %s
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
"tPO1" : %.3f,
|
||||
"tPO2" : %.3f,
|
||||
"tPO3" : %.3f,
|
||||
"t" : "%s"
|
||||
"t" : %s
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name" : "%s%s",
|
||||
"stat_t" : "%s%s",
|
||||
"uniq_id" : "%s_%s",
|
||||
"obj_id" : "%s_%s",
|
||||
"default_entity_id" : "sensor.%s_%s",
|
||||
"val_tpl" : "{{ value_json.%s | is_defined }}",
|
||||
"expire_after" : %d,
|
||||
"dev" : {
|
||||
|
||||
@@ -28,7 +28,8 @@ void HomeAssistantMqttHandler::setHomeAssistantConfig(HomeAssistantConfig config
|
||||
snprintf_P(json, 128, PSTR("[%s] "), config.discoveryNameTag);
|
||||
sensorNamePrefix = String(json);
|
||||
} else {
|
||||
deviceName = F("AMS reader");
|
||||
snprintf_P(json, 128, PSTR("AMS reader"));
|
||||
deviceName = String(json);
|
||||
sensorNamePrefix = "";
|
||||
}
|
||||
deviceModel = boardTypeToString(boardType);
|
||||
@@ -52,20 +53,18 @@ void HomeAssistantMqttHandler::setHomeAssistantConfig(HomeAssistantConfig config
|
||||
deviceUrl = String(json);
|
||||
}
|
||||
|
||||
if(strlen(config.discoveryPrefix) > 0) {
|
||||
snprintf_P(json, 128, PSTR("%s/status"), config.discoveryPrefix);
|
||||
statusTopic = String(json);
|
||||
|
||||
snprintf_P(json, 128, PSTR("%s/sensor"), config.discoveryPrefix);
|
||||
sensorTopic = String(json);
|
||||
|
||||
snprintf_P(json, 128, PSTR("%s/update"), config.discoveryPrefix);
|
||||
updateTopic = String(json);
|
||||
} else {
|
||||
statusTopic = F("homeassistant/status");
|
||||
sensorTopic = F("homeassistant/sensor");
|
||||
updateTopic = F("homeassistant/update");
|
||||
if(strlen(config.discoveryPrefix) == 0) {
|
||||
snprintf_P(config.discoveryPrefix, 64, PSTR("homeassistant"));
|
||||
}
|
||||
|
||||
snprintf_P(json, 128, PSTR("%s/status"), config.discoveryPrefix);
|
||||
statusTopic = String(json);
|
||||
|
||||
snprintf_P(json, 128, PSTR("%s/sensor"), config.discoveryPrefix);
|
||||
sensorTopic = String(json);
|
||||
|
||||
snprintf_P(json, 128, PSTR("%s/update"), config.discoveryPrefix);
|
||||
updateTopic = String(json);
|
||||
strcpy(this->mqttConfig.subscribeTopic, statusTopic.c_str());
|
||||
}
|
||||
|
||||
@@ -134,12 +133,7 @@ bool HomeAssistantMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea)
|
||||
publishList1Sensors();
|
||||
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(data->getPackageTimestamp() > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(data->getPackageTimestamp(), tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(data->getPackageTimestamp(), pt, sizeof(pt));
|
||||
|
||||
snprintf_P(json, BufferSize, HA1_JSON, data->getActiveImportPower(), pt);
|
||||
return mqtt.publish(pubTopic + "/power", json);
|
||||
@@ -150,12 +144,7 @@ bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea)
|
||||
if(data->getActiveExportPower() > 0) publishList2ExportSensors();
|
||||
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(data->getPackageTimestamp() > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(data->getPackageTimestamp(), tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(data->getPackageTimestamp(), pt, sizeof(pt));
|
||||
|
||||
snprintf_P(json, BufferSize, HA3_JSON,
|
||||
data->getListId().c_str(),
|
||||
@@ -181,20 +170,11 @@ bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea)
|
||||
if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors();
|
||||
|
||||
char mt[24];
|
||||
memset(mt, 0, 24);
|
||||
if(data->getMeterTimestamp() > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(data->getMeterTimestamp(), tm);
|
||||
sprintf_P(mt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(data->getMeterTimestamp(), mt, sizeof(mt));
|
||||
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(data->getPackageTimestamp() > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(data->getPackageTimestamp(), tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(data->getPackageTimestamp(), pt, sizeof(pt));
|
||||
|
||||
snprintf_P(json, BufferSize, HA2_JSON,
|
||||
data->getActiveImportCounter(),
|
||||
@@ -212,12 +192,7 @@ bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea)
|
||||
if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors();
|
||||
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(data->getPackageTimestamp() > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(data->getPackageTimestamp(), tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(data->getPackageTimestamp(), pt, sizeof(pt));
|
||||
|
||||
snprintf_P(json, BufferSize, HA4_JSON,
|
||||
data->getListId().c_str(),
|
||||
@@ -307,13 +282,8 @@ bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting*
|
||||
|
||||
time_t now = time(nullptr);
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(now > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt);
|
||||
toJsonIsoTimestamp(now, pt, sizeof(pt));
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":%s"), pt);
|
||||
|
||||
json[pos++] = '}';
|
||||
json[pos] = '\0';
|
||||
@@ -343,13 +313,8 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT
|
||||
|
||||
time_t now = time(nullptr);
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(now > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt);
|
||||
toJsonIsoTimestamp(now, pt, sizeof(pt));
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":%s"), pt);
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("}"));
|
||||
|
||||
bool ret = mqtt.publish(pubTopic + "/temperatures", json);
|
||||
@@ -421,25 +386,34 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts1hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts1hr, sizeof(ts1hr));
|
||||
}
|
||||
char ts3hr[24];
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts3hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts3hr, sizeof(ts3hr));
|
||||
}
|
||||
char ts6hr[24];
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts6hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts6hr, sizeof(ts6hr));
|
||||
}
|
||||
|
||||
uint16_t pos = snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"prices\":{\"import\":["), WiFi.macAddress().c_str());
|
||||
@@ -468,7 +442,7 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("],\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":\"%s\",\"cheapest3hr\":\"%s\",\"cheapest6hr\":\"%s\"}"),
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("],\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":%s,\"cheapest3hr\":%s,\"cheapest6hr\":%s}"),
|
||||
min == INT16_MAX ? 0.0 : min,
|
||||
max == INT16_MIN ? 0.0 : max,
|
||||
ts1hr,
|
||||
@@ -477,13 +451,8 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
);
|
||||
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(now > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt);
|
||||
toJsonIsoTimestamp(now, pt, sizeof(pt));
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":%s"), pt);
|
||||
|
||||
json[pos++] = '}';
|
||||
json[pos] = '\0';
|
||||
@@ -502,14 +471,9 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, PriceService* ps, Ener
|
||||
|
||||
time_t now = time(nullptr);
|
||||
char pt[24];
|
||||
memset(pt, 0, 24);
|
||||
if(now > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
}
|
||||
toJsonIsoTimestamp(now, pt, sizeof(pt));
|
||||
|
||||
snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"name\":\"%s\",\"up\":%d,\"vcc\":%.3f,\"rssi\":%d,\"temp\":%.2f,\"version\":\"%s\",\"t\":\"%s\"}"),
|
||||
snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"name\":\"%s\",\"up\":%d,\"vcc\":%.3f,\"rssi\":%d,\"temp\":%.2f,\"version\":\"%s\",\"t\":%s}"),
|
||||
WiFi.macAddress().c_str(),
|
||||
mqttConfig.clientId,
|
||||
(uint32_t) (millis64()/1000),
|
||||
@@ -902,3 +866,14 @@ void HomeAssistantMqttHandler::onMessage(String &topic, String &payload) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::toJsonIsoTimestamp(time_t t, char* buf, size_t buflen) {
|
||||
memset(buf, 0, buflen);
|
||||
if(t > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(t, tm);
|
||||
snprintf_P(buf, buflen, PSTR("\"%04d-%02d-%02dT%02d:%02d:%02dZ\""), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
} else {
|
||||
snprintf_P(buf, buflen, PSTR("null"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
bool applyBoardConfig(uint8_t boardType, GpioConfig& gpioConfig, MeterConfig& meterConfig, uint8_t hanPin);
|
||||
void setup(SystemConfig* sys, GpioConfig* gpio);
|
||||
float getVcc();
|
||||
void setMaxVcc(float maxVcc);
|
||||
uint8_t getTempSensorCount();
|
||||
TempSensorData* getTempSensorData(uint8_t);
|
||||
bool updateTemperatures();
|
||||
@@ -68,7 +69,7 @@ private:
|
||||
uint8_t vccPin, vccGnd_r, vccVcc_r;
|
||||
float vccOffset, vccMultiplier;
|
||||
float vcc = 3.3; // Last known Vcc
|
||||
float maxVcc = 3.25; // Best to have this close to max as a start, in case Pow-U reboots and starts off with a low voltage, we dont want that to be perceived as max
|
||||
float maxVcc = 3.28; // Best to have this close to max as a start, in case Pow-U reboots and starts off with a low voltage, we dont want that to be perceived as max
|
||||
unsigned long lastVccRead = 0;
|
||||
|
||||
uint16_t analogRange = 1024;
|
||||
|
||||
@@ -677,4 +677,8 @@ bool HwTools::isVoltageOptimal(float range) {
|
||||
|
||||
uint8_t HwTools::getBoardType() {
|
||||
return boardType;
|
||||
}
|
||||
|
||||
void HwTools::setMaxVcc(float vcc) {
|
||||
this->maxVcc = min(3.3f, vcc);
|
||||
}
|
||||
@@ -42,5 +42,6 @@ private:
|
||||
bool publishList3(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList4(AmsData* data, EnergyAccounting* ea);
|
||||
String getMeterModel(AmsData* data);
|
||||
void toJsonIsoTimestamp(time_t t, char* buf, size_t buflen);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -356,25 +356,34 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts1hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts1hr, sizeof(ts1hr));
|
||||
}
|
||||
char ts3hr[24];
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts3hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts3hr, sizeof(ts3hr));
|
||||
}
|
||||
char ts6hr[24];
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
tmElements_t tm;
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts6hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
ts = makeTime(tm);
|
||||
toJsonIsoTimestamp(ts, ts6hr, sizeof(ts6hr));
|
||||
}
|
||||
|
||||
if(mqttConfig.payloadFormat == 6) {
|
||||
@@ -388,7 +397,7 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
}
|
||||
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"pr_min\":%.4f,\"pr_max\":%.4f,\"pr_cheapest1hr\":\"%s\",\"pr_cheapest3hr\":\"%s\",\"pr_cheapest6hr\":\"%s\"}"),
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"pr_min\":%.4f,\"pr_max\":%.4f,\"pr_cheapest1hr\":%s,\"pr_cheapest3hr\":%s,\"pr_cheapest6hr\":%s}"),
|
||||
min == INT16_MAX ? 0.0 : min,
|
||||
max == INT16_MIN ? 0.0 : max,
|
||||
ts1hr,
|
||||
@@ -422,7 +431,7 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("],\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":\"%s\",\"cheapest3hr\":\"%s\",\"cheapest6hr\":\"%s\"}}"),
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("],\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":%s,\"cheapest3hr\":%s,\"cheapest6hr\":%s}}"),
|
||||
min == INT16_MAX ? 0.0 : min,
|
||||
max == INT16_MIN ? 0.0 : max,
|
||||
ts1hr,
|
||||
@@ -535,3 +544,14 @@ void JsonMqttHandler::onMessage(String &topic, String &payload) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonMqttHandler::toJsonIsoTimestamp(time_t t, char* buf, size_t buflen) {
|
||||
memset(buf, 0, buflen);
|
||||
if(t > 0) {
|
||||
tmElements_t tm;
|
||||
breakTime(t, tm);
|
||||
snprintf_P(buf, buflen, PSTR("\"%04d-%02d-%02dT%02d:%02d:%02dZ\""), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
|
||||
} else {
|
||||
snprintf_P(buf, buflen, PSTR("null"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,206 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC
|
||||
if(val == NOVALUE) {
|
||||
CosemData* data = getCosemDataAt(1, ((char *) (d)));
|
||||
|
||||
// Kaifa special case...
|
||||
if(useMeterType == AmsTypeKaifa && data->base.type == CosemTypeDLongUnsigned) {
|
||||
this->packageTimestamp = this->packageTimestamp > 0 && tz != NULL ? tz->toUTC(this->packageTimestamp) : 0;
|
||||
if(useMeterType == AmsTypeIskra) { // Iskra special case
|
||||
meterType = AmsTypeIskra;
|
||||
uint8_t idx = 0;
|
||||
data = getCosemDataAt(idx, ((char *) (d)));
|
||||
if(data->base.length == 0x21) {
|
||||
idx = 4;
|
||||
|
||||
// 1.8.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
|
||||
// 1.8.1
|
||||
// 1.8.2
|
||||
idx += 2;
|
||||
|
||||
// 2.8.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
|
||||
// 2.8.1
|
||||
// 2.8.2
|
||||
idx += 2;
|
||||
|
||||
// 5.8.0
|
||||
// 6.8.0
|
||||
// 7.8.0
|
||||
// 8.8.0
|
||||
idx += 4;
|
||||
|
||||
// 1.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeImportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 2.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeExportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 13.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
powerFactor= ntohl(data->dlu.data) / 1000.0;
|
||||
|
||||
// 21.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1activeImportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 41.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l2activeImportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 61.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3activeImportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 22.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1activeExportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 42.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l2activeExportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 62.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3activeExportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 32.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1voltage = ntohs(data->lu.data) / 10.0;
|
||||
|
||||
// 52.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l2voltage = ntohs(data->lu.data) / 10.0;
|
||||
|
||||
// 72.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3voltage = ntohs(data->lu.data) / 10.0;
|
||||
|
||||
// 31.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
// 51.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l2current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
// 71.7.0
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
listType = 4;
|
||||
lastUpdateMillis = millis64();
|
||||
} else if(data->base.length == 0x0F) {
|
||||
idx = 1;
|
||||
|
||||
// 1.8.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
|
||||
// 1.8.1 ?
|
||||
// 1.8.2 ?
|
||||
idx += 2;
|
||||
|
||||
// 2.8.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
|
||||
// 2.8.1 ?
|
||||
// 2.8.2 ?
|
||||
idx += 2;
|
||||
|
||||
idx++; // Unknown empty octet string
|
||||
|
||||
CosemData* meterTs = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(meterTs != NULL) {
|
||||
AmsOctetTimestamp* amst = (AmsOctetTimestamp*) meterTs;
|
||||
time_t ts = decodeCosemDateTime(amst->dt);
|
||||
meterTimestamp = ts;
|
||||
}
|
||||
|
||||
// 2.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeExportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 1.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeImportPower = ntohl(data->dlu.data);
|
||||
|
||||
// 31.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
// 51.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l2current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
// 71.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3current = ntohs(data->lu.data) / 100.0;
|
||||
|
||||
// 32.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l1voltage = ntohs(data->lu.data) / 10.0;
|
||||
|
||||
// 72.7.0 ?
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
l3voltage = ntohs(data->lu.data) / 10.0;
|
||||
|
||||
// 52.7.0 missing?
|
||||
l2voltage = sqrt(pow(l1voltage - l3voltage * cos(60 * (PI/180)), 2) + pow(l3voltage * sin(60 * (PI/180)),2));
|
||||
|
||||
listType = 3;
|
||||
lastUpdateMillis = millis64();
|
||||
} else {
|
||||
idx = 5;
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
reactiveImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
reactiveExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeImportPower = ntohl(data->dlu.data);
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeExportPower = ntohl(data->dlu.data);
|
||||
}
|
||||
|
||||
uint8_t str_len = 0;
|
||||
str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str);
|
||||
if(str_len > 0) {
|
||||
meterId = String(str);
|
||||
}
|
||||
|
||||
listType = 4;
|
||||
lastUpdateMillis = millis64();
|
||||
}
|
||||
} else if(useMeterType == AmsTypeKaifa && data->base.type == CosemTypeDLongUnsigned) { // Kaifa special case
|
||||
listType = 1;
|
||||
meterType = AmsTypeKaifa;
|
||||
activeImportPower = ntohl(data->dlu.data);
|
||||
lastUpdateMillis = millis64();
|
||||
} else if(data->base.type == CosemTypeOctetString) {
|
||||
this->packageTimestamp = this->packageTimestamp > 0 && tz != NULL ? tz->toUTC(this->packageTimestamp) : 0;
|
||||
|
||||
} else if(data->base.type == CosemTypeOctetString) { // Assuming first string is a list identifier
|
||||
memcpy(str, data->oct.data, data->oct.length);
|
||||
str[data->oct.length] = 0x00;
|
||||
String listId = String(str);
|
||||
@@ -42,7 +232,7 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC
|
||||
this->listId = listId;
|
||||
meterType = AmsTypeKaifa;
|
||||
|
||||
int idx = 0;
|
||||
uint8_t idx = 0;
|
||||
data = getCosemDataAt(idx, ((char *) (d)));
|
||||
idx+=2;
|
||||
if(data->base.length == 0x0D || data->base.length == 0x12) {
|
||||
@@ -144,7 +334,7 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC
|
||||
this->listId = listId;
|
||||
meterType = AmsTypeIskra;
|
||||
|
||||
int idx = 0;
|
||||
uint8_t idx = 0;
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data->base.length == 0x12) {
|
||||
apply(state);
|
||||
@@ -559,49 +749,31 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
activeExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
} else if(useMeterType == AmsTypeIskra && data->base.type == CosemTypeOctetString) { // Iskra special case
|
||||
}
|
||||
}
|
||||
|
||||
if(meterType == AmsTypeUnknown && useMeterType == AmsTypeUnknown) {
|
||||
debugger->println("AMS unknown meter type, trying to identify...");
|
||||
CosemData* d1 = getCosemDataAt(1, ((char *) (d)));
|
||||
CosemData* d2 = getCosemDataAt(2, ((char *) (d)));
|
||||
CosemData* d3 = getCosemDataAt(3, ((char *) (d)));
|
||||
CosemData* d7 = getCosemDataAt(7, ((char *) (d)));
|
||||
CosemData* d8 = getCosemDataAt(8, ((char *) (d)));
|
||||
|
||||
if(d1->base.type == CosemTypeDLongUnsigned &&
|
||||
d2->base.type == CosemTypeDLongUnsigned &&
|
||||
d3->base.type == CosemTypeDLongUnsigned &&
|
||||
d7->base.type == CosemTypeOctetString &&
|
||||
d8->base.type == CosemTypeOctetString
|
||||
) {
|
||||
meterType = AmsTypeIskra;
|
||||
uint8_t idx = 5;
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
reactiveImportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
reactiveExportCounter = ntohl(data->dlu.data) / 1000.0;
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeImportPower = ntohl(data->dlu.data);
|
||||
}
|
||||
|
||||
data = getCosemDataAt(idx++, ((char *) (d)));
|
||||
if(data != NULL) {
|
||||
activeExportPower = ntohl(data->dlu.data);
|
||||
}
|
||||
|
||||
uint8_t str_len = 0;
|
||||
str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str);
|
||||
if(str_len > 0) {
|
||||
meterId = String(str);
|
||||
}
|
||||
|
||||
listType = 3;
|
||||
lastUpdateMillis = millis64();
|
||||
} else if(useMeterType == AmsTypeUnknown) {
|
||||
listType = 3;
|
||||
} else if(d1->base.type == CosemTypeOctetString && d2->base.type == CosemTypeOctetString && d3->base.type == CosemTypeOctetString) {
|
||||
meterType = AmsTypeIskra;
|
||||
lastUpdateMillis = millis64();
|
||||
listType = 3;
|
||||
} else {
|
||||
uint8_t str_len = 0;
|
||||
str_len = getString(AMS_OBIS_UNKNOWN_1, sizeof(AMS_OBIS_UNKNOWN_1), ((char *) (d)), str);
|
||||
if(str_len > 0) {
|
||||
@@ -612,7 +784,7 @@ IEC6205675::IEC6205675(const char* d, Timezone* tz, uint8_t useMeterType, MeterC
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else { // OBIS code parsing
|
||||
listType = 1;
|
||||
activeImportPower = val;
|
||||
|
||||
|
||||
@@ -807,6 +807,7 @@ void PassiveMeterCommunicator::rxerr(int err) {
|
||||
#endif
|
||||
debugger->printf_P(PSTR("Serial buffer overflow\n"));
|
||||
rxBufferErrors++;
|
||||
#if defined(ESP32)
|
||||
if(rxBufferErrors > 1 && meterConfig.bufferSize < 8) {
|
||||
meterConfig.bufferSize += 2;
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
@@ -816,6 +817,7 @@ void PassiveMeterCommunicator::rxerr(int err) {
|
||||
configChanged = true;
|
||||
rxBufferErrors = 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
this->topic = String(mqttConfig.publishTopic);
|
||||
};
|
||||
#else
|
||||
PassthroughMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf) : AmsMqttHandler(mqttConfig, debugger, buf) {
|
||||
PassthroughMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
|
||||
this->topic = String(mqttConfig.publishTopic);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -124,9 +124,6 @@ private:
|
||||
Timezone* tz = NULL;
|
||||
Timezone* entsoeTz = NULL;
|
||||
|
||||
static const uint16_t BufferSize = 256;
|
||||
char* buf;
|
||||
|
||||
bool hub = false;
|
||||
uint8_t* key = NULL;
|
||||
uint8_t* auth = NULL;
|
||||
@@ -139,7 +136,7 @@ private:
|
||||
bool retrieve(const char* url, Stream* doc);
|
||||
float getCurrencyMultiplier(const char* from, const char* to, time_t t);
|
||||
bool timeIsInPeriod(tmElements_t tm, PriceConfig pc);
|
||||
float getFixedPrice(uint8_t direction, int8_t hour);
|
||||
float getFixedPrice(uint8_t direction, int8_t point);
|
||||
float getEnergyPricePoint(uint8_t direction, uint8_t point);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -25,8 +25,6 @@ PriceService::PriceService(RemoteDebug* Debug) : priceConfig(std::vector<PriceCo
|
||||
#else
|
||||
PriceService::PriceService(Stream* Debug) : priceConfig(std::vector<PriceConfig>()) {
|
||||
#endif
|
||||
this->buf = (char*) malloc(BufferSize);
|
||||
|
||||
debugger = Debug;
|
||||
|
||||
// Entso-E uses CET/CEST
|
||||
@@ -129,15 +127,16 @@ bool PriceService::isExportPricesDifferentFromImport() {
|
||||
}
|
||||
|
||||
float PriceService::getPricePoint(uint8_t direction, uint8_t point) {
|
||||
float value = getFixedPrice(direction, point * getResolutionInMinutes() / 60);
|
||||
float value = getFixedPrice(direction, point);
|
||||
if(value == PRICE_NO_VALUE) value = getEnergyPricePoint(direction, point);
|
||||
if(value == PRICE_NO_VALUE) return PRICE_NO_VALUE;
|
||||
|
||||
tmElements_t tm;
|
||||
time_t ts = time(nullptr);
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
breakTime(entsoeTz->toLocal(ts), tm);
|
||||
tm.Hour = tm.Minute = tm.Second = 0;
|
||||
breakTime(makeTime(tm) + (point * SECS_PER_MIN * getResolutionInMinutes()), tm);
|
||||
ts = entsoeTz->toUTC(makeTime(tm)) + (point * SECS_PER_MIN * getResolutionInMinutes());
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
|
||||
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
||||
PriceConfig pc = priceConfig.at(i);
|
||||
@@ -164,8 +163,6 @@ float PriceService::getPricePoint(uint8_t direction, uint8_t point) {
|
||||
|
||||
float PriceService::getCurrentPrice(uint8_t direction) {
|
||||
time_t ts = time(nullptr);
|
||||
tmElements_t tm;
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
uint8_t pos = getCurrentPricePointIndex();
|
||||
|
||||
return getPricePoint(direction, pos);
|
||||
@@ -173,6 +170,7 @@ float PriceService::getCurrentPrice(uint8_t direction) {
|
||||
|
||||
float PriceService::getEnergyPricePoint(uint8_t direction, uint8_t point) {
|
||||
uint8_t pos = point;
|
||||
|
||||
float multiplier = 1.0;
|
||||
uint8_t numberOfPointsToday = 24;
|
||||
if(today != NULL) {
|
||||
@@ -208,10 +206,10 @@ float PriceService::getPriceForRelativeHour(uint8_t direction, int8_t hour) {
|
||||
time_t ts = time(nullptr);
|
||||
tmElements_t tm;
|
||||
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
int8_t targetHour = tm.Hour + hour;
|
||||
breakTime(entsoeTz->toLocal(ts), tm);
|
||||
uint8_t targetHour = tm.Hour + hour;
|
||||
tm.Hour = tm.Minute = tm.Second = 0;
|
||||
time_t startOfDay = tz->toUTC(makeTime(tm));
|
||||
time_t startOfDay = entsoeTz->toUTC(makeTime(tm));
|
||||
|
||||
if((ts + (hour * SECS_PER_HOUR)) < startOfDay) {
|
||||
return PRICE_NO_VALUE;
|
||||
@@ -237,15 +235,15 @@ float PriceService::getPriceForRelativeHour(uint8_t direction, int8_t hour) {
|
||||
return valueSum / valueCount;
|
||||
}
|
||||
|
||||
float PriceService::getFixedPrice(uint8_t direction, int8_t hour) {
|
||||
float PriceService::getFixedPrice(uint8_t direction, int8_t point) {
|
||||
time_t ts = time(nullptr);
|
||||
|
||||
tmElements_t tm;
|
||||
breakTime(entsoeTz->toLocal(ts), tm);
|
||||
tm.Hour = tm.Minute = tm.Second = 0;
|
||||
ts = entsoeTz->toUTC(makeTime(tm)) + (point * SECS_PER_MIN * getResolutionInMinutes());
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
tm.Hour = hour;
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
breakTime(makeTime(tm), tm);
|
||||
tm.Minute = tm.Second = 0;
|
||||
|
||||
float value = PRICE_NO_VALUE;
|
||||
for (uint8_t i = 0; i < priceConfig.size(); i++) {
|
||||
@@ -430,11 +428,12 @@ float PriceService::getCurrencyMultiplier(const char* from, const char* to, time
|
||||
#endif
|
||||
|
||||
float currencyMultiplier = 0;
|
||||
snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/B.%s.NOK.SP?lastNObservations=1"), from);
|
||||
char buf[80];
|
||||
snprintf_P(buf, 80, PSTR("https://data.norges-bank.no/api/data/EXR/B.%s.NOK.SP?lastNObservations=1"), from);
|
||||
if(retrieve(buf, &p)) {
|
||||
currencyMultiplier = p.getValue();
|
||||
if(strncmp(to, "NOK", 3) != 0) {
|
||||
snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/B.%s.NOK.SP?lastNObservations=1"), to);
|
||||
snprintf_P(buf, 80, PSTR("https://data.norges-bank.no/api/data/EXR/B.%s.NOK.SP?lastNObservations=1"), to);
|
||||
if(retrieve(buf, &p)) {
|
||||
if(p.getValue() > 0.0) {
|
||||
currencyMultiplier /= p.getValue();
|
||||
@@ -477,7 +476,8 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
breakTime(e1, d1);
|
||||
breakTime(e2, d2);
|
||||
|
||||
snprintf_P(buf, BufferSize, PSTR("https://web-api.tp.entsoe.eu/api?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s"),
|
||||
char buf[256];
|
||||
snprintf_P(buf, 256, PSTR("https://web-api.tp.entsoe.eu/api?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s"),
|
||||
getToken(),
|
||||
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
|
||||
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
|
||||
@@ -514,8 +514,8 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
tmElements_t tm;
|
||||
breakTime(entsoeTz->toLocal(t), tm);
|
||||
|
||||
String data;
|
||||
snprintf_P(buf, BufferSize, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d/pt%dm?currency=%s"),
|
||||
char buf[128];
|
||||
snprintf_P(buf, 128, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d/pt%dm?currency=%s"),
|
||||
config->area,
|
||||
tm.Year+1970,
|
||||
tm.Month,
|
||||
@@ -547,13 +547,14 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
#endif
|
||||
|
||||
if(status == HTTP_CODE_OK) {
|
||||
data = http->getString();
|
||||
http->end();
|
||||
|
||||
uint8_t* content = (uint8_t*) (data.c_str());
|
||||
uint8_t content[1024];
|
||||
|
||||
WiFiClient* stream = http->getStreamPtr();
|
||||
|
||||
DataParserContext ctx = {0,0,0,0};
|
||||
ctx.length = data.length();
|
||||
ctx.length = stream->readBytes(content, http->getSize());
|
||||
http->end();
|
||||
|
||||
GCMParser gcm(key, auth);
|
||||
int8_t gcmRet = gcm.parse(content, ctx);
|
||||
if(gcmRet > 0) {
|
||||
@@ -569,8 +570,11 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
ret->setCurrency(header->currency);
|
||||
int32_t* points = (int32_t*) &header[1];
|
||||
|
||||
for(uint8_t i = 0; i < header->numberOfPoints; i++) {
|
||||
int32_t intval = ntohl(points[i]);
|
||||
int32_t intval;
|
||||
for(uint8_t i = 0; i < ret->getNumberOfPoints(); i++) {
|
||||
// To avoid alignment issues on ESP8266, we use memcpy
|
||||
memcpy(&intval, &points[i], sizeof(int32_t));
|
||||
intval = ntohl(intval); // Change byte order before converting to float, to support negative values
|
||||
float value = intval / 10000.0;
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
if (debugger->isActive(RemoteDebug::VERBOSE))
|
||||
@@ -579,8 +583,10 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
ret->setPrice(i, value, PRICE_DIRECTION_IMPORT);
|
||||
}
|
||||
if(header->differentExportPrices) {
|
||||
for(uint8_t i = 0; i < header->numberOfPoints; i++) {
|
||||
int32_t intval = ntohl(points[i]);
|
||||
for(uint8_t i = 0; i < ret->getNumberOfPoints(); i++) {
|
||||
// To avoid alignment issues on ESP8266, we use memcpy
|
||||
memcpy(&intval, &points[ret->getNumberOfPoints()+i], sizeof(int32_t));
|
||||
intval = ntohl(intval); // Change byte order before converting to float, to support negative values
|
||||
float value = intval / 10000.0;
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
if (debugger->isActive(RemoteDebug::VERBOSE))
|
||||
@@ -756,6 +762,6 @@ bool PriceService::timeIsInPeriod(tmElements_t tm, PriceConfig pc) {
|
||||
uint8_t PriceService::getCurrentPricePointIndex() {
|
||||
time_t ts = time(nullptr);
|
||||
tmElements_t tm;
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
breakTime(entsoeTz->toLocal(ts), tm);
|
||||
return ((tm.Hour * 60) + tm.Minute) / getResolutionInMinutes();
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
topic = String(mqttConfig.publishTopic);
|
||||
};
|
||||
#else
|
||||
RawMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf) : AmsMqttHandler(mqttConfig, debugger, buf) {
|
||||
RawMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
|
||||
full = mqttConfig.payloadFormat == 2;
|
||||
topic = String(mqttConfig.publishTopic);
|
||||
};
|
||||
|
||||
16
lib/SvelteUi/app/dist/index.js
vendored
16
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
11
lib/SvelteUi/app/package-lock.json
generated
11
lib/SvelteUi/app/package-lock.json
generated
@@ -9,7 +9,8 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"cssnano": "^5.1.15",
|
||||
"esbuild": ">=0.25.0"
|
||||
"esbuild": ">=0.25.0",
|
||||
"ipaddr.js": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
||||
@@ -1584,6 +1585,14 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz",
|
||||
"integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"overrides": {
|
||||
"svelte-navigator": {
|
||||
"svelte": ">=4.x"
|
||||
}
|
||||
},
|
||||
"svelte-navigator": {
|
||||
"svelte": ">=4.x"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
@@ -30,6 +30,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano": "^5.1.15",
|
||||
"esbuild": ">=0.25.0"
|
||||
"esbuild": ">=0.25.0",
|
||||
"ipaddr.js": "^2.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
{#each config.x.ticks as point, i}
|
||||
{#if !isNaN(xScale(i))}
|
||||
<g class="tick" transform="translate({xScale(i)},{heightAvailable})">
|
||||
{#if barWidth > 20 || i%2 == 0}
|
||||
{#if barWidth > 20 || i%2 == 0 || !config.x.ticks[i-1].label}
|
||||
<text x="{barWidth/2}" y="-4">{point.label}</text>
|
||||
{/if}
|
||||
</g>
|
||||
|
||||
@@ -140,17 +140,17 @@
|
||||
{#if uiVisibility(sysinfo.ui.p, data.p && !Number.isNaN(data.p))}
|
||||
{#if importPrices?.importExportPriceDifferent && (data.om || data.e > 0)}
|
||||
<div class="cnt gwf">
|
||||
<PricePlot title="{translations.dashboard?.price_import ?? "Price import"}" json={importPrices}/>
|
||||
<PricePlot title="{translations.dashboard?.price_import ?? "Price import"}" json={importPrices} sysinfo={sysinfo}/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="cnt gwf">
|
||||
<PricePlot title={translations.dashboard?.price ?? "Price"} json={importPrices}/>
|
||||
<PricePlot title={translations.dashboard?.price ?? "Price"} json={importPrices} sysinfo={sysinfo}/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if importPrices?.importExportPriceDifferent && (data.om || data.e > 0) && uiVisibility(sysinfo.ui.p, data.pe && !Number.isNaN(data.pe))}
|
||||
<div class="cnt gwf">
|
||||
<PricePlot title={translations.dashboard?.price_export ?? "Price export"} json={exportPrices}/>
|
||||
<PricePlot title={translations.dashboard?.price_export ?? "Price export"} json={exportPrices} sysinfo={sysinfo}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.d, dayPlot)}
|
||||
|
||||
@@ -130,7 +130,7 @@ export function uiVisibility(choice, state) {
|
||||
}
|
||||
|
||||
export function wiki(page) {
|
||||
let ret = "https://wiki.amsleser.no/";
|
||||
let ret = "https://wiki.amsleser.no";
|
||||
if(page) {
|
||||
ret += "/en/firmware#" + page;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
export let title;
|
||||
export let json;
|
||||
export let sysinfo;
|
||||
|
||||
let config = {};
|
||||
let max;
|
||||
@@ -39,7 +40,8 @@
|
||||
let xTicks = [];
|
||||
let values = [];
|
||||
min = max = 0;
|
||||
let i = Math.floor(((cur.getHours()*60) + cur.getMinutes()) / json?.resolution);
|
||||
addHours(cur, sysinfo.clock_offset - ((24 + cur.getHours() - cur.getUTCHours())%24));
|
||||
let i = json?.cursor ? json.cursor : 0;
|
||||
cur.setMinutes(Math.floor(cur.getMinutes()/json?.resolution)*json?.resolution,0,0);
|
||||
while(i < json?.prices?.length) {
|
||||
val = json.prices[i];
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import Clock from './Clock.svelte';
|
||||
import Mask from './Mask.svelte';
|
||||
import { scanForDevice } from './Helpers.js';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
|
||||
export let data;
|
||||
export let sysinfo;
|
||||
@@ -207,11 +208,11 @@
|
||||
</div>
|
||||
{#if sysinfo.net.ipv6}
|
||||
<div class="my-2">
|
||||
IPv6: <span style="font-size: 14px;">{sysinfo.net.ipv6.replace(/\b:?(?:0+:?){2,}/, '::')}</span>
|
||||
IPv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.ipv6)}</span>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
{#if sysinfo.net.dns1v6}DNSv6: <span style="font-size: 14px;">{sysinfo.net.dns1v6.replace(/\b:?(?:0+:?){2,}/, '::')}</span>{/if}
|
||||
{#if sysinfo.net.dns2v6}DNSv6: <span style="font-size: 14px;">{sysinfo.net.dns2v6.replace(/\b:?(?:0+:?){2,}/, '::')}</span>{/if}
|
||||
{#if sysinfo.net.dns1v6}DNSv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.dns1v6)}</span>{/if}
|
||||
{#if sysinfo.net.dns2v6}DNSv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.dns2v6)}</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "%s",
|
||||
"chip": "%s",
|
||||
"chipId": "%s",
|
||||
"chipId": "%06x",
|
||||
"cpu": %d,
|
||||
"mac": "%s",
|
||||
"apmac": "%s",
|
||||
|
||||
@@ -306,22 +306,14 @@ void AmsWebServer::sysinfoJson() {
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
uint32_t chipId;
|
||||
#if defined(ESP32)
|
||||
chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF;
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
String chipIdStr = String(chipId, HEX);
|
||||
|
||||
String hostname;
|
||||
|
||||
char hostname[32];
|
||||
if(sys.userConfigured) {
|
||||
NetworkConfig networkConfig;
|
||||
config->getNetworkConfig(networkConfig);
|
||||
hostname = String(networkConfig.hostname);
|
||||
strncpy(hostname, networkConfig.hostname, 32);
|
||||
} else {
|
||||
hostname = "ams-"+chipIdStr;
|
||||
config->getUniqueName(hostname, 32);
|
||||
}
|
||||
|
||||
IPAddress localIp;
|
||||
@@ -421,7 +413,7 @@ void AmsWebServer::sysinfoJson() {
|
||||
#elif defined(ESP8266)
|
||||
"esp8266",
|
||||
#endif
|
||||
chipIdStr.c_str(),
|
||||
config->getChipId(),
|
||||
cpu_freq,
|
||||
macStr,
|
||||
apMacStr,
|
||||
@@ -429,7 +421,7 @@ void AmsWebServer::sysinfoJson() {
|
||||
sys.vendorConfigured ? "true" : "false",
|
||||
sys.userConfigured ? "true" : "false",
|
||||
sys.dataCollectionConsent,
|
||||
hostname.c_str(),
|
||||
hostname,
|
||||
performRestart ? "true" : "false",
|
||||
updater->getProgress() > 0.0 && upinfo.errorCode == 0 ? "true" : "false",
|
||||
#if defined(ESP8266)
|
||||
@@ -777,11 +769,12 @@ void AmsWebServer::priceJson(uint8_t direction) {
|
||||
prices[i] = ps->getPricePoint(direction, i);
|
||||
}
|
||||
|
||||
snprintf_P(buf, BufferSize, PSTR("{\"currency\":\"%s\",\"source\":\"%s\",\"resolution\":%d,\"direction\":\"%s\",\"importExportPriceDifferent\":%s,\"prices\":["),
|
||||
snprintf_P(buf, BufferSize, PSTR("{\"currency\":\"%s\",\"source\":\"%s\",\"resolution\":%d,\"direction\":\"%s\",\"cursor\":%d,\"importExportPriceDifferent\":%s,\"prices\":["),
|
||||
ps->getCurrency(),
|
||||
ps->getSource(),
|
||||
ps->getResolutionInMinutes(),
|
||||
direction == PRICE_DIRECTION_IMPORT ? "import" : direction == PRICE_DIRECTION_EXPORT ? "export" : "both",
|
||||
ps->getCurrentPricePointIndex(),
|
||||
ps->isExportPricesDifferentFromImport() ? "true" : "false"
|
||||
);
|
||||
|
||||
@@ -1388,10 +1381,10 @@ void AmsWebServer::handleSave() {
|
||||
memset(meterConfig.authenticationKey, 0, 16);
|
||||
}
|
||||
|
||||
meterConfig.wattageMultiplier = server.arg(F("mmw")).toFloat() * 1000;
|
||||
meterConfig.voltageMultiplier = server.arg(F("mmv")).toFloat() * 1000;
|
||||
meterConfig.amperageMultiplier = server.arg(F("mma")).toFloat() * 1000;
|
||||
meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toFloat() * 1000;
|
||||
meterConfig.wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000.0;
|
||||
meterConfig.voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000.0;
|
||||
meterConfig.amperageMultiplier = server.arg(F("mma")).toDouble() * 1000.0;
|
||||
meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000.0;
|
||||
config->setMeterConfig(meterConfig);
|
||||
}
|
||||
|
||||
@@ -1407,7 +1400,7 @@ void AmsWebServer::handleSave() {
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(network.psk, psk.c_str());
|
||||
}
|
||||
network.power = server.arg(F("ww")).toFloat() * 10;
|
||||
network.power = server.arg(F("ww")).toDouble() * 10.0;
|
||||
network.sleep = server.arg(F("wz")).toInt();
|
||||
network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true");
|
||||
}
|
||||
@@ -1568,9 +1561,9 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("iv")) && server.arg(F("iv")) == F("true")) {
|
||||
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toFloat() * 100 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toFloat() * 1000 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toFloat() * 10 : 0;
|
||||
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toDouble() * 100.0 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toDouble() * 1000.0 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toDouble() * 10.0 : 0;
|
||||
config->setGpioConfig(*gpioConfig);
|
||||
}
|
||||
|
||||
@@ -1685,7 +1678,7 @@ void AmsWebServer::handleSave() {
|
||||
snprintf_P(buf, BufferSize, PSTR("rd%d"), i);
|
||||
pc.direction = server.arg(buf).toInt();
|
||||
snprintf_P(buf, BufferSize, PSTR("rv%d"), i);
|
||||
pc.value = server.arg(buf).toFloat() * 10000;
|
||||
pc.value = server.arg(buf).toDouble() * 10000.0;
|
||||
snprintf_P(buf, BufferSize, PSTR("rn%d"), i);
|
||||
String name = server.arg(buf);
|
||||
strcpy(pc.name, name.c_str());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
extra_configs = platformio-user.ini
|
||||
|
||||
[common]
|
||||
lib_deps = EEPROM, LittleFS, DNSServer, 256dpi/MQTT@2.5.2, OneWireNg@0.13.3, DallasTemperature@4.0.4, https://github.com/gskjold/RemoteDebug.git, PaulStoffregen/Time@1.6.1, JChristensen/Timezone@1.2.4, bblanchon/ArduinoJson@7.0.4, FirmwareVersion, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, PriceService, EnergyAccounting, AmsFirmwareUpdater, AmsJsonGenerator, AmsMqttHandler, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, PassthroughMqttHandler, RealtimePlot, ConnectionHandler, MeterCommunicators
|
||||
lib_deps = EEPROM, LittleFS, DNSServer, 256dpi/MQTT@2.5.2, OneWireNg@0.13.3, DallasTemperature@4.0.4, https://github.com/gskjold/RemoteDebug.git, PaulStoffregen/Time@1.6.1, JChristensen/Timezone@1.2.4, FirmwareVersion, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, PriceService, EnergyAccounting, AmsFirmwareUpdater, AmsJsonGenerator, AmsMqttHandler, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, PassthroughMqttHandler, RealtimePlot, ConnectionHandler, MeterCommunicators
|
||||
lib_ignore = OneWire
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
@@ -19,7 +19,7 @@ build_flags =
|
||||
-fexceptions
|
||||
|
||||
[esp32]
|
||||
lib_deps = WiFi, Ethernet, ESPmDNS, WiFiClientSecure, HTTPClient, FS, WebServer, ESP32 Async UDP, ESP32SSDP, mulmer89/ESPRandom@1.5.0, ${common.lib_deps}, CloudConnector, ZmartCharge, SvelteUi
|
||||
lib_deps = WiFi, Ethernet, ESPmDNS, WiFiClientSecure, HTTPClient, FS, WebServer, ESP32 Async UDP, ESP32SSDP, mulmer89/ESPRandom@1.5.0, ${common.lib_deps}, bblanchon/ArduinoJson@7.0.4, CloudConnector, ZmartCharge, SvelteUi
|
||||
|
||||
[env:esp8266]
|
||||
platform = espressif8266@4.2.1
|
||||
|
||||
@@ -190,10 +190,15 @@ CloudConnector *cloud = NULL;
|
||||
#if defined(ZMART_CHARGE)
|
||||
ZmartChargeCloudConnector *zcloud = NULL;
|
||||
#endif
|
||||
|
||||
#define MAX_BOOT_CYCLES 6
|
||||
|
||||
#if defined(ESP32)
|
||||
__NOINIT_ATTR EnergyAccountingRealtimeData rtd;
|
||||
RTC_DATA_ATTR uint8_t bootcount = 0;
|
||||
#else
|
||||
EnergyAccountingRealtimeData rtd;
|
||||
uint32_t bootcount = 0;
|
||||
#endif
|
||||
EnergyAccounting ea(&Debug, &rtd);
|
||||
|
||||
@@ -326,6 +331,31 @@ void rxerr(int err) {
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t incrementBootCycleCounter(bool deepSleep) {
|
||||
#if defined(ESP8266)
|
||||
if(deepSleep) {
|
||||
if(ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount))) {
|
||||
bootcount++;
|
||||
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
|
||||
}
|
||||
return bootcount;
|
||||
} else {
|
||||
return ++bootcount;
|
||||
}
|
||||
#else
|
||||
return ++bootcount;
|
||||
#endif
|
||||
}
|
||||
void resetBootCycleCounter(bool deepSleep) {
|
||||
#if defined(ESP8266)
|
||||
bootcount = 0;
|
||||
if(deepSleep) {
|
||||
ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount));
|
||||
}
|
||||
#else
|
||||
bootcount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
@@ -380,20 +410,6 @@ void setup() {
|
||||
}
|
||||
}
|
||||
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
hw.ledBlink(LED_RED, 1);
|
||||
hw.ledBlink(LED_YELLOW, 1);
|
||||
hw.ledBlink(LED_GREEN, 1);
|
||||
hw.ledBlink(LED_BLUE, 1);
|
||||
|
||||
PriceServiceConfig price;
|
||||
if(config.getPriceServiceConfig(price)) {
|
||||
ps = new PriceService(&Debug);
|
||||
ps->setup(price);
|
||||
ws.setPriceService(ps);
|
||||
}
|
||||
ws.setPriceSettings(price.area, price.currency);
|
||||
ea.setCurrency(price.currency);
|
||||
bool shared = false;
|
||||
Serial.flush();
|
||||
Serial.end();
|
||||
@@ -441,22 +457,51 @@ void setup() {
|
||||
yield();
|
||||
#endif
|
||||
|
||||
float vcc = hw.getVcc();
|
||||
|
||||
if(!hw.ledOn(LED_YELLOW)) {
|
||||
hw.ledOn(LED_INTERNAL);
|
||||
}
|
||||
debugI_P(PSTR("AMS reader %s started"), FirmwareVersion::VersionString);
|
||||
debugI_P(PSTR("Configuration version: %d, board type: %d"), config.getConfigVersion(), sysConfig.boardType);
|
||||
float vcc = hw.getVcc();
|
||||
debugI_P(PSTR("Voltage: %.2fV"), vcc);
|
||||
|
||||
float vccBootLimit = gpioConfig.vccBootLimit == 0 ? 0 : min(3.29, gpioConfig.vccBootLimit / 10.0); // Make sure it is never above 3.3v
|
||||
if(vcc > 2.5 && vccBootLimit > 2.5 && vccBootLimit < 3.3 && (gpioConfig.apPin == 0xFF || digitalRead(gpioConfig.apPin) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released)
|
||||
if (vcc < vccBootLimit) {
|
||||
{
|
||||
Debug.printf_P(PSTR("(setup) Voltage is too low (%.2f < %.2f), sleeping\n"), vcc, vccBootLimit);
|
||||
bool deepSleep = true;
|
||||
#if defined(ESP32)
|
||||
float allowedDrift = bootcount * 0.01;
|
||||
#else
|
||||
float allowedDrift = gpioConfig.vccBootLimit == 0 ? 0.05 : 3.3 - min(3.29, gpioConfig.vccBootLimit / 10.0); // Make sure boot limit is never above 3.3v
|
||||
deepSleep = gpioConfig.vccBootLimit > 0; // If a boot limit is set, we are assume the hardware has been configured for deep sleep (Hint: GPIO16)
|
||||
#endif
|
||||
while(!hw.isVoltageOptimal(allowedDrift)) {
|
||||
uint8_t bootCycles = incrementBootCycleCounter(deepSleep);
|
||||
debugW_P(PSTR("Voltage is outside optimal range (%.2fV)"), allowedDrift);
|
||||
if(gpioConfig.apPin != 0xFF && digitalRead(gpioConfig.apPin) == LOW) {
|
||||
debugW_P(PSTR("AP button is pressed, skipping voltage wait"));
|
||||
} else if(bootCycles < MAX_BOOT_CYCLES) {
|
||||
int secs = MAX_BOOT_CYCLES - bootCycles;
|
||||
if(deepSleep) {
|
||||
debugI_P(PSTR("Sleeping for %d seconds to allow capacitor charge (%d.cycle)"), secs, bootCycles);
|
||||
Serial.flush();
|
||||
ESP.deepSleep(secs * 1000000); // Deep sleep to allow output cap to charge up
|
||||
return;
|
||||
} else {
|
||||
debugI_P(PSTR("Waiting (no sleep) for %d seconds to allow capacitor charge (%d.cycle)"), secs, bootCycles);
|
||||
delay(secs * 1000); // Just delay to allow output cap to charge up
|
||||
vcc = hw.getVcc();
|
||||
debugI_P(PSTR("Voltage: %.2fV"), vcc);
|
||||
}
|
||||
ESP.deepSleep(10000000); //Deep sleep to allow output cap to charge up
|
||||
}
|
||||
} else {
|
||||
debugE_P(PSTR("Voltage not reaching optimal level after multiple attempts, continuing boot"));
|
||||
hw.setMaxVcc(vcc); // Since we had to sleep, set max Vcc to current level because this is probably the highest we will get
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(ESP8266)
|
||||
resetBootCycleCounter(deepSleep);
|
||||
#endif
|
||||
hw.ledOff(LED_YELLOW);
|
||||
hw.ledOff(LED_INTERNAL);
|
||||
|
||||
if(!hw.ledOn(LED_GREEN)) {
|
||||
hw.ledOn(LED_INTERNAL);
|
||||
@@ -472,6 +517,12 @@ void setup() {
|
||||
hw.ledOff(LED_GREEN);
|
||||
hw.ledOff(LED_INTERNAL);
|
||||
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
hw.ledBlink(LED_RED, 1);
|
||||
hw.ledBlink(LED_YELLOW, 1);
|
||||
hw.ledBlink(LED_GREEN, 1);
|
||||
hw.ledBlink(LED_BLUE, 1);
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
@@ -537,6 +588,15 @@ void setup() {
|
||||
toggleSetupMode();
|
||||
}
|
||||
|
||||
PriceServiceConfig price;
|
||||
if(config.getPriceServiceConfig(price)) {
|
||||
ps = new PriceService(&Debug);
|
||||
ps->setup(price);
|
||||
ws.setPriceService(ps);
|
||||
}
|
||||
ws.setPriceSettings(price.area, price.currency);
|
||||
ea.setCurrency(price.currency);
|
||||
|
||||
EnergyAccountingConfig *eac = new EnergyAccountingConfig();
|
||||
if(!config.getEnergyAccountingConfig(*eac)) {
|
||||
config.clearEnergyAccountingConfig(*eac);
|
||||
@@ -633,7 +693,12 @@ void loop() {
|
||||
handleEnergySpeedometer();
|
||||
#endif
|
||||
#endif
|
||||
handlePriceService(now);
|
||||
|
||||
// In case of BUS powered meters, we need to be sure voltage is stable before fetching prices. But we refuse to wait forever, so max 30 seconds
|
||||
if(now > 30000 || hw.isVoltageOptimal(0.01)) {
|
||||
handlePriceService(now);
|
||||
}
|
||||
|
||||
#if defined(AMS_CLOUD)
|
||||
handleCloud();
|
||||
#endif
|
||||
@@ -655,7 +720,7 @@ void loop() {
|
||||
}
|
||||
|
||||
communicationTime += handleWebserver();
|
||||
if(communicationTime > 10 && updater.getProgress() >= 0) {
|
||||
if(communicationTime > 25 && updater.getProgress() >= 0) {
|
||||
debugI_P(PSTR("Communication is active (%dms), forcing updater to wait"), communicationTime);
|
||||
} else {
|
||||
handleUpdater();
|
||||
@@ -836,13 +901,7 @@ void handleEnergySpeedometer() {
|
||||
if(sysConfig.energyspeedometer == 7) {
|
||||
if(!meterState.getMeterId().isEmpty()) {
|
||||
if(energySpeedometer == NULL) {
|
||||
uint16_t chipId;
|
||||
#if defined(ESP32)
|
||||
chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF;
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
strcpy(energySpeedometerConfig.clientId, (String("ams") + String(chipId, HEX)).c_str());
|
||||
config.getUniqueName(energySpeedometerConfig.clientId, 32);
|
||||
energySpeedometer = new JsonMqttHandler(energySpeedometerConfig, &Debug, (char*) commonBuffer, &hw, &ds, &updater);
|
||||
energySpeedometer->setCaVerification(false);
|
||||
}
|
||||
@@ -1044,7 +1103,13 @@ void handleMeterConfig() {
|
||||
debugE_P(PSTR("Unknown meter source selected: %d"), meterConfig.source);
|
||||
}
|
||||
ws.setMeterConfig(meterConfig.distributionSystem, meterConfig.mainFuse, meterConfig.productionCapacity);
|
||||
if(mc != NULL && Debug.isActive(RemoteDebug::DEBUG)) {
|
||||
if(mc != NULL &&
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
Debug.isActive(RemoteDebug::DEBUG)
|
||||
#else
|
||||
false // Never send debug data
|
||||
#endif
|
||||
) {
|
||||
mc->setMqttHandlerForDebugging(mqttHandler);
|
||||
}
|
||||
config.ackMeterChanged();
|
||||
@@ -1389,17 +1454,29 @@ void toggleSetupMode() {
|
||||
#else
|
||||
WiFi.beginSmartConfig();
|
||||
#endif
|
||||
WiFi.softAP(PSTR("AMS2MQTT"));
|
||||
|
||||
char ssid[32];
|
||||
if(sysConfig.vendorConfigured) {
|
||||
// Use the standard SSID if the vendor has configured the device
|
||||
strcpy_P(ssid, PSTR("AMS2MQTT"));
|
||||
} else {
|
||||
// If not vendor configured, use a unique SSID to avoid conflicts if multiple devices are in setup mode at the same time
|
||||
config.getUniqueName(ssid, 32);
|
||||
}
|
||||
uint8_t debugLevel = RemoteDebug::INFO;
|
||||
#if defined(DEBUG_MODE)
|
||||
debugLevel = RemoteDebug::VERBOSE;
|
||||
#endif
|
||||
WiFi.softAP(ssid);
|
||||
Debug.setSerialEnabled(true);
|
||||
Debug.begin(F("192.168.4.1"), 23, debugLevel);
|
||||
debugI_P(PSTR("SSID: %s"), ssid);
|
||||
|
||||
if(dnsServer == NULL) {
|
||||
dnsServer = new DNSServer();
|
||||
}
|
||||
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer->start(53, PSTR("*"), WiFi.softAPIP());
|
||||
#if defined(DEBUG_MODE)
|
||||
Debug.setSerialEnabled(true);
|
||||
Debug.begin(F("192.168.4.1"), 23, RemoteDebug::VERBOSE);
|
||||
#endif
|
||||
setupMode = true;
|
||||
|
||||
hw.setBootSuccessful(false);
|
||||
@@ -1563,7 +1640,13 @@ void postConnect() {
|
||||
if(!debug.telnet) {
|
||||
Debug.stop();
|
||||
}
|
||||
if(mc != NULL && Debug.isActive(RemoteDebug::DEBUG)) {
|
||||
if(mc != NULL &&
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
Debug.isActive(RemoteDebug::DEBUG)
|
||||
#else
|
||||
false // Never send debug data
|
||||
#endif
|
||||
) {
|
||||
mc->setMqttHandlerForDebugging(mqttHandler);
|
||||
}
|
||||
} else {
|
||||
@@ -1695,7 +1778,13 @@ void MQTT_connect() {
|
||||
}
|
||||
}
|
||||
ws.setMqttHandler(mqttHandler);
|
||||
if(mc != NULL && Debug.isActive(RemoteDebug::DEBUG)) {
|
||||
if(mc != NULL &&
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
Debug.isActive(RemoteDebug::DEBUG)
|
||||
#else
|
||||
false // Never send debug data
|
||||
#endif
|
||||
) {
|
||||
mc->setMqttHandlerForDebugging(mqttHandler);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user