Merge remote-tracking branch
'tbnobody/OpenDTU/master'
This commit is contained in:
commit
3febc28c78
@ -64,7 +64,7 @@ Sends text raw data as difined in VE.Direct spec.
|
|||||||
* Show inverters internal event log
|
* Show inverters internal event log
|
||||||
* Show inverter information like firmware version, firmware build date, hardware revision and hardware version
|
* Show inverter information like firmware version, firmware build date, hardware revision and hardware version
|
||||||
* Show and set the current inverter limit
|
* Show and set the current inverter limit
|
||||||
* Function to turn the inverter off an on
|
* Function to turn the inverter off and on
|
||||||
* Uses ESP32 microcontroller and NRF24L01+
|
* Uses ESP32 microcontroller and NRF24L01+
|
||||||
* Multi-Inverter support
|
* Multi-Inverter support
|
||||||
* MQTT support (with TLS)
|
* MQTT support (with TLS)
|
||||||
|
|||||||
@ -61,6 +61,7 @@ cmd topics are used to set values. Status topics are updated from values set in
|
|||||||
| Topic | R / W | Description | Value / Unit |
|
| Topic | R / W | Description | Value / Unit |
|
||||||
| ----------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
|
| ----------------------------------------- | ----- | ---------------------------------------------------- | -------------------------- |
|
||||||
| [serial]/status/limit_relative | R | Current applied production limit of the inverter | % of total possible output |
|
| [serial]/status/limit_relative | R | Current applied production limit of the inverter | % of total possible output |
|
||||||
|
| [serial]/status/limit_absolute | R | Current applied production limit of the inverter | Watt (W) |
|
||||||
| [serial]/status/reachable | R | Indicates whether the inverter is reachable | 0 or 1 |
|
| [serial]/status/reachable | R | Indicates whether the inverter is reachable | 0 or 1 |
|
||||||
| [serial]/status/producing | R | Indicates whether the inverter is producing AC power | 0 or 1 |
|
| [serial]/status/producing | R | Indicates whether the inverter is producing AC power | 0 or 1 |
|
||||||
| [serial]/cmd/limit_persistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
| [serial]/cmd/limit_persistent_relative | W | Set the inverter limit as a percentage of total production capability. The value will survive the night without power. The updated value will show up in the web GUI and limit_relative topic immediatly. | % |
|
||||||
|
|||||||
@ -48,6 +48,7 @@ void HoymilesRadio::loop()
|
|||||||
f = _rxBuffer.getFront();
|
f = _rxBuffer.getFront();
|
||||||
memset(f->fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
memset(f->fragment, 0xcc, MAX_RF_PAYLOAD_SIZE);
|
||||||
f->len = _radio->getDynamicPayloadSize();
|
f->len = _radio->getDynamicPayloadSize();
|
||||||
|
f->channel = _radio->getChannel();
|
||||||
if (f->len > MAX_RF_PAYLOAD_SIZE)
|
if (f->len > MAX_RF_PAYLOAD_SIZE)
|
||||||
f->len = MAX_RF_PAYLOAD_SIZE;
|
f->len = MAX_RF_PAYLOAD_SIZE;
|
||||||
|
|
||||||
@ -69,7 +70,9 @@ void HoymilesRadio::loop()
|
|||||||
|
|
||||||
if (nullptr != inv) {
|
if (nullptr != inv) {
|
||||||
// Save packet in inverter rx buffer
|
// Save packet in inverter rx buffer
|
||||||
dumpBuf("RX ", f->fragment, f->len);
|
char buf[30];
|
||||||
|
snprintf(buf, sizeof(buf), "RX Channel: %d --> ", f->channel);
|
||||||
|
dumpBuf(buf, f->fragment, f->len);
|
||||||
inv->addRxFragment(f->fragment, f->len);
|
inv->addRxFragment(f->fragment, f->len);
|
||||||
} else {
|
} else {
|
||||||
Serial.println(F("Inverter Not found!"));
|
Serial.println(F("Inverter Not found!"));
|
||||||
@ -161,6 +164,11 @@ bool HoymilesRadio::isIdle()
|
|||||||
return !_busyFlag;
|
return !_busyFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HoymilesRadio::isConnected()
|
||||||
|
{
|
||||||
|
return _radio->isChipConnected();
|
||||||
|
}
|
||||||
|
|
||||||
void HoymilesRadio::openReadingPipe()
|
void HoymilesRadio::openReadingPipe()
|
||||||
{
|
{
|
||||||
serial_u s;
|
serial_u s;
|
||||||
|
|||||||
@ -46,9 +46,7 @@ public:
|
|||||||
void setDtuSerial(uint64_t serial);
|
void setDtuSerial(uint64_t serial);
|
||||||
|
|
||||||
bool isIdle();
|
bool isIdle();
|
||||||
void sendEsbPacket(CommandAbstract* cmd);
|
bool isConnected();
|
||||||
void sendRetransmitPacket(uint8_t fragment_id);
|
|
||||||
void sendLastPacketAgain();
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* enqueCommand()
|
T* enqueCommand()
|
||||||
@ -68,6 +66,10 @@ private:
|
|||||||
bool checkFragmentCrc(fragment_t* fragment);
|
bool checkFragmentCrc(fragment_t* fragment);
|
||||||
void dumpBuf(const char* info, uint8_t buf[], uint8_t len);
|
void dumpBuf(const char* info, uint8_t buf[], uint8_t len);
|
||||||
|
|
||||||
|
void sendEsbPacket(CommandAbstract* cmd);
|
||||||
|
void sendRetransmitPacket(uint8_t fragment_id);
|
||||||
|
void sendLastPacketAgain();
|
||||||
|
|
||||||
std::unique_ptr<SPIClass> _hspi;
|
std::unique_ptr<SPIClass> _hspi;
|
||||||
std::unique_ptr<RF24> _radio;
|
std::unique_ptr<RF24> _radio;
|
||||||
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
uint8_t _rxChLst[5] = { 3, 23, 40, 61, 75 };
|
||||||
|
|||||||
@ -49,7 +49,12 @@ bool ActivePowerControlCommand::handleResponse(InverterAbstract* inverter, fragm
|
|||||||
if ((getType() == PowerLimitControlType::RelativNonPersistent) || (getType() == PowerLimitControlType::RelativPersistent)) {
|
if ((getType() == PowerLimitControlType::RelativNonPersistent) || (getType() == PowerLimitControlType::RelativPersistent)) {
|
||||||
inverter->SystemConfigPara()->setLimitPercent(getLimit());
|
inverter->SystemConfigPara()->setLimitPercent(getLimit());
|
||||||
} else {
|
} else {
|
||||||
// TODO(tbnobody): Not implemented yet because we only can publish the percentage value
|
uint16_t max_power = inverter->DevInfo()->getMaxPower();
|
||||||
|
if (max_power > 0) {
|
||||||
|
inverter->SystemConfigPara()->setLimitPercent(static_cast<float>(getLimit()) / max_power * 100);
|
||||||
|
} else {
|
||||||
|
// TODO(tbnobody): Not implemented yet because we only can publish the percentage value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inverter->SystemConfigPara()->setLastUpdateCommand(millis());
|
inverter->SystemConfigPara()->setLastUpdateCommand(millis());
|
||||||
inverter->SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK);
|
inverter->SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ AlarmDataCommand::AlarmDataCommand(uint64_t target_address, uint64_t router_addr
|
|||||||
{
|
{
|
||||||
setTime(time);
|
setTime(time);
|
||||||
setDataType(0x11);
|
setDataType(0x11);
|
||||||
setTimeout(500);
|
setTimeout(600);
|
||||||
}
|
}
|
||||||
|
|
||||||
String AlarmDataCommand::getCommandName()
|
String AlarmDataCommand::getCommandName()
|
||||||
|
|||||||
@ -5,7 +5,22 @@ HM_1CH::HM_1CH(uint64_t serial)
|
|||||||
|
|
||||||
bool HM_1CH::isValidSerial(uint64_t serial)
|
bool HM_1CH::isValidSerial(uint64_t serial)
|
||||||
{
|
{
|
||||||
return serial >= 0x112100000000 && serial <= 0x112199999999;
|
// serial >= 0x112100000000 && serial <= 0x112199999999
|
||||||
|
|
||||||
|
uint8_t preId[2];
|
||||||
|
preId[0] = (uint8_t)(serial >> 40);
|
||||||
|
preId[1] = (uint8_t)(serial >> 32);
|
||||||
|
|
||||||
|
if ((uint8_t)(((((uint16_t)preId[0] << 8) | preId[1]) >> 4) & 0xff) == 0x12) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((preId[1] & 0xf0) == 0x10) || ((preId[1] & 0xf0) == 0x20))
|
||||||
|
&& (((preId[0] == 0x10) && (preId[1] == 0x22)) || ((preId[0] == 0x11) && (preId[1] == 0x21)))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String HM_1CH::typeName()
|
String HM_1CH::typeName()
|
||||||
|
|||||||
@ -5,7 +5,22 @@ HM_2CH::HM_2CH(uint64_t serial)
|
|||||||
|
|
||||||
bool HM_2CH::isValidSerial(uint64_t serial)
|
bool HM_2CH::isValidSerial(uint64_t serial)
|
||||||
{
|
{
|
||||||
return serial >= 0x114100000000 && serial <= 0x114199999999;
|
// serial >= 0x114100000000 && serial <= 0x114199999999
|
||||||
|
|
||||||
|
uint8_t preId[2];
|
||||||
|
preId[0] = (uint8_t)(serial >> 40);
|
||||||
|
preId[1] = (uint8_t)(serial >> 32);
|
||||||
|
|
||||||
|
if ((uint8_t)(((((uint16_t)preId[0] << 8) | preId[1]) >> 4) & 0xff) == 0x14) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((preId[1] & 0xf0) == 0x30) || ((preId[1] & 0xf0) == 0x40))
|
||||||
|
&& (((preId[0] == 0x10) && (preId[1] == 0x42)) || ((preId[0] == 0x11) && (preId[1] == 0x41)))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String HM_2CH::typeName()
|
String HM_2CH::typeName()
|
||||||
|
|||||||
@ -5,12 +5,27 @@ HM_4CH::HM_4CH(uint64_t serial)
|
|||||||
|
|
||||||
bool HM_4CH::isValidSerial(uint64_t serial)
|
bool HM_4CH::isValidSerial(uint64_t serial)
|
||||||
{
|
{
|
||||||
return serial >= 0x116100000000 && serial <= 0x116199999999;
|
// serial >= 0x116100000000 && serial <= 0x116199999999
|
||||||
|
|
||||||
|
uint8_t preId[2];
|
||||||
|
preId[0] = (uint8_t)(serial >> 40);
|
||||||
|
preId[1] = (uint8_t)(serial >> 32);
|
||||||
|
|
||||||
|
if ((uint8_t)(((((uint16_t)preId[0] << 8) | preId[1]) >> 4) & 0xff) == 0x16) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((preId[1] & 0xf0) == 0x50) || ((preId[1] & 0xf0) == 0x60))
|
||||||
|
&& (((preId[0] == 0x10) && (preId[1] == 0x62)) || ((preId[0] == 0x11) && (preId[1] == 0x61)))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String HM_4CH::typeName()
|
String HM_4CH::typeName()
|
||||||
{
|
{
|
||||||
return String(F("HM-1200, HM-1500"));
|
return String(F("HM-1000, HM-1200, HM-1500"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const byteAssign_t* HM_4CH::getByteAssignment()
|
const byteAssign_t* HM_4CH::getByteAssignment()
|
||||||
|
|||||||
@ -1,6 +1,23 @@
|
|||||||
#include "DevInfoParser.h"
|
#include "DevInfoParser.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t hwPart[3];
|
||||||
|
uint16_t maxPower;
|
||||||
|
const char* modelName;
|
||||||
|
} devInfo_t;
|
||||||
|
|
||||||
|
const devInfo_t devInfo[] = {
|
||||||
|
{ { 0x10, 0x10, 0x10 }, 300, "HM-300" },
|
||||||
|
{ { 0x10, 0x10, 0x20 }, 350, "HM-350" },
|
||||||
|
{ { 0x10, 0x10, 0x40 }, 400, "HM-400" },
|
||||||
|
{ { 0x10, 0x11, 0x10 }, 600, "HM-600" },
|
||||||
|
{ { 0x10, 0x11, 0x20 }, 700, "HM-700" },
|
||||||
|
{ { 0x10, 0x11, 0x40 }, 800, "HM-800" },
|
||||||
|
{ { 0x10, 0x12, 0x10 }, 1200, "HM-1200" },
|
||||||
|
{ { 0x10, 0x12, 0x30 }, 1500, "HM-1500" }
|
||||||
|
};
|
||||||
|
|
||||||
void DevInfoParser::clearBufferAll()
|
void DevInfoParser::clearBufferAll()
|
||||||
{
|
{
|
||||||
memset(_payloadDevInfoAll, 0, DEV_INFO_SIZE);
|
memset(_payloadDevInfoAll, 0, DEV_INFO_SIZE);
|
||||||
@ -92,9 +109,40 @@ uint32_t DevInfoParser::getHwPartNumber()
|
|||||||
|
|
||||||
String DevInfoParser::getHwVersion()
|
String DevInfoParser::getHwVersion()
|
||||||
{
|
{
|
||||||
char buf[6];
|
char buf[8];
|
||||||
snprintf(buf, sizeof(buf), "%02X.%02X", _payloadDevInfoSimple[6], _payloadDevInfoSimple[7]);
|
snprintf(buf, sizeof(buf), "%02d.%02d", _payloadDevInfoSimple[6], _payloadDevInfoSimple[7]);
|
||||||
return String(buf);
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t DevInfoParser::getMaxPower()
|
||||||
|
{
|
||||||
|
uint8_t idx = getDevIdx();
|
||||||
|
if (idx == 0xff) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return devInfo[idx].maxPower;
|
||||||
|
}
|
||||||
|
|
||||||
|
String DevInfoParser::getHwModelName()
|
||||||
|
{
|
||||||
|
uint8_t idx = getDevIdx();
|
||||||
|
if (idx == 0xff) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return devInfo[idx].modelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DevInfoParser::getDevIdx()
|
||||||
|
{
|
||||||
|
uint8_t pos;
|
||||||
|
for (pos = 0; pos < sizeof(devInfo) / sizeof(devInfo_t); pos++) {
|
||||||
|
if (devInfo[pos].hwPart[0] == _payloadDevInfoSimple[2]
|
||||||
|
&& devInfo[pos].hwPart[1] == _payloadDevInfoSimple[3]
|
||||||
|
&& devInfo[pos].hwPart[2] == _payloadDevInfoSimple[4]) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* struct tm to seconds since Unix epoch */
|
/* struct tm to seconds since Unix epoch */
|
||||||
|
|||||||
@ -25,8 +25,12 @@ public:
|
|||||||
uint32_t getHwPartNumber();
|
uint32_t getHwPartNumber();
|
||||||
String getHwVersion();
|
String getHwVersion();
|
||||||
|
|
||||||
|
uint16_t getMaxPower();
|
||||||
|
String getHwModelName();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
time_t timegm(struct tm* tm);
|
time_t timegm(struct tm* tm);
|
||||||
|
uint8_t getDevIdx();
|
||||||
|
|
||||||
uint32_t _lastUpdateAll = 0;
|
uint32_t _lastUpdateAll = 0;
|
||||||
uint32_t _lastUpdateSimple = 0;
|
uint32_t _lastUpdateSimple = 0;
|
||||||
|
|||||||
@ -14,5 +14,6 @@ typedef struct {
|
|||||||
uint8_t mainCmd;
|
uint8_t mainCmd;
|
||||||
uint8_t fragment[MAX_RF_PAYLOAD_SIZE];
|
uint8_t fragment[MAX_RF_PAYLOAD_SIZE];
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
uint8_t channel;
|
||||||
bool wasReceived;
|
bool wasReceived;
|
||||||
} fragment_t;
|
} fragment_t;
|
||||||
|
|||||||
@ -65,6 +65,11 @@ void MqttPublishingClass::loop()
|
|||||||
if (inv->SystemConfigPara()->getLastUpdate() > 0) {
|
if (inv->SystemConfigPara()->getLastUpdate() > 0) {
|
||||||
// Limit
|
// Limit
|
||||||
MqttSettings.publish(subtopic + "/status/limit_relative", String(inv->SystemConfigPara()->getLimitPercent()));
|
MqttSettings.publish(subtopic + "/status/limit_relative", String(inv->SystemConfigPara()->getLimitPercent()));
|
||||||
|
|
||||||
|
uint16_t maxpower = inv->DevInfo()->getMaxPower();
|
||||||
|
if (maxpower > 0) {
|
||||||
|
MqttSettings.publish(subtopic + "/status/limit_absolute", String(inv->SystemConfigPara()->getLimitPercent() * maxpower / 100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttSettings.publish(subtopic + "/status/reachable", String(inv->isReachable()));
|
MqttSettings.publish(subtopic + "/status/reachable", String(inv->isReachable()));
|
||||||
|
|||||||
@ -41,6 +41,7 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
|||||||
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
|
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
|
||||||
devInfoObj[F("hw_part_number")] = inv->DevInfo()->getHwPartNumber();
|
devInfoObj[F("hw_part_number")] = inv->DevInfo()->getHwPartNumber();
|
||||||
devInfoObj[F("hw_version")] = inv->DevInfo()->getHwVersion();
|
devInfoObj[F("hw_version")] = inv->DevInfo()->getHwVersion();
|
||||||
|
devInfoObj[F("hw_model_name")] = inv->DevInfo()->getHwModelName();
|
||||||
|
|
||||||
char timebuffer[32];
|
char timebuffer[32];
|
||||||
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
||||||
|
|||||||
@ -35,7 +35,7 @@ void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
|
|||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
||||||
|
|
||||||
root[buffer]["limit"] = inv->SystemConfigPara()->getLimitPercent();
|
root[buffer]["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
||||||
|
|
||||||
LastCommandSuccess status = inv->SystemConfigPara()->getLastLimitCommandSuccess();
|
LastCommandSuccess status = inv->SystemConfigPara()->getLastLimitCommandSuccess();
|
||||||
String limitStatus = "Unknown";
|
String limitStatus = "Unknown";
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
|
#include <Hoymiles.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#include <ResetReason.h>
|
#include <ResetReason.h>
|
||||||
|
|
||||||
@ -64,6 +65,8 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
root[F("uptime")] = esp_timer_get_time() / 1000000;
|
root[F("uptime")] = esp_timer_get_time() / 1000000;
|
||||||
|
|
||||||
|
root[F("radio_connected")] = Hoymiles.getRadio()->isConnected();
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
@ -495,7 +495,7 @@ export default defineComponent({
|
|||||||
fetch("/api/limit/status")
|
fetch("/api/limit/status")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.currentLimit = data[serial].limit;
|
this.currentLimit = data[serial].limit_relative;
|
||||||
this.successCommandLimit = data[serial].limit_set_status;
|
this.successCommandLimit = data[serial].limit_set_status;
|
||||||
this.limitSettingSerial = serial;
|
this.limitSettingSerial = serial;
|
||||||
this.limitSettingLoading = false;
|
this.limitSettingLoading = false;
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
<div class="mt-5"></div>
|
<div class="mt-5"></div>
|
||||||
<MemoryInfo v-bind="systemDataList" />
|
<MemoryInfo v-bind="systemDataList" />
|
||||||
<div class="mt-5"></div>
|
<div class="mt-5"></div>
|
||||||
|
<RadioInfo v-bind="systemDataList" />
|
||||||
|
<div class="mt-5"></div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -26,12 +28,14 @@ import { defineComponent } from 'vue';
|
|||||||
import HardwareInfo from "@/components/partials/HardwareInfo.vue";
|
import HardwareInfo from "@/components/partials/HardwareInfo.vue";
|
||||||
import FirmwareInfo from "@/components/partials/FirmwareInfo.vue";
|
import FirmwareInfo from "@/components/partials/FirmwareInfo.vue";
|
||||||
import MemoryInfo from "@/components/partials/MemoryInfo.vue";
|
import MemoryInfo from "@/components/partials/MemoryInfo.vue";
|
||||||
|
import RadioInfo from "@/components/partials/RadioInfo.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
HardwareInfo,
|
HardwareInfo,
|
||||||
FirmwareInfo,
|
FirmwareInfo,
|
||||||
MemoryInfo,
|
MemoryInfo,
|
||||||
|
RadioInfo,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -60,7 +64,9 @@ export default defineComponent({
|
|||||||
littlefs_total: 0,
|
littlefs_total: 0,
|
||||||
littlefs_used: 0,
|
littlefs_used: 0,
|
||||||
sketch_total: 0,
|
sketch_total: 0,
|
||||||
sketch_used: 0
|
sketch_used: 0,
|
||||||
|
// RadioInfo
|
||||||
|
radio_connected: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,6 +6,12 @@
|
|||||||
</BootstrapAlert>
|
</BootstrapAlert>
|
||||||
<table v-if="devInfoList.valid_data" class="table table-hover">
|
<table v-if="devInfoList.valid_data" class="table table-hover">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Model</td>
|
||||||
|
<td v-if="devInfoList.hw_model_name != ''">{{ devInfoList.hw_model_name }}</td>
|
||||||
|
<td v-else>Unknown model! Please report the "Hardware Part Number" and model (e.g. HM-350) as an issue
|
||||||
|
<a href="https://github.com/tbnobody/OpenDTU/issues" target="_blank">here</a>.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Bootloader Version</td>
|
<td>Bootloader Version</td>
|
||||||
<td>{{ formatVersion(devInfoList.fw_bootloader_version) }}</td>
|
<td>{{ formatVersion(devInfoList.fw_bootloader_version) }}</td>
|
||||||
@ -40,7 +46,8 @@ declare interface DevInfoData {
|
|||||||
fw_build_version: number,
|
fw_build_version: number,
|
||||||
fw_build_datetime: Date,
|
fw_build_datetime: Date,
|
||||||
hw_part_number: number,
|
hw_part_number: number,
|
||||||
hw_version: number
|
hw_version: number,
|
||||||
|
hw_model_name: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
|||||||
@ -41,14 +41,20 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
timeInHours() {
|
timeInHours() {
|
||||||
return (value: number) => {
|
return (value: number) => {
|
||||||
const hours = Math.floor((value) / 3600);
|
const days = Math.floor(value / (24 * 60 * 60));
|
||||||
const minutes = Math.floor((value - hours * 3600) / 60);
|
const secAfterDays = value - days * (24 * 60 * 60);
|
||||||
const seconds = (value - hours * 3600 + minutes * 60) % 60;
|
const hours = Math.floor(secAfterDays / (60 * 60));
|
||||||
|
const secAfterHours = secAfterDays - hours * (60 * 60);
|
||||||
|
const minutes = Math.floor(secAfterHours / 60);
|
||||||
|
const seconds = secAfterHours - minutes * 60;
|
||||||
|
|
||||||
const dHours = hours > 9 ? hours : "0" + hours;
|
const dHours = hours > 9 ? hours : "0" + hours;
|
||||||
const dMins = minutes > 9 ? minutes : "0" + minutes;
|
const dMins = minutes > 9 ? minutes : "0" + minutes;
|
||||||
const dSecs = seconds > 9 ? seconds : "0" + seconds;
|
const dSecs = seconds > 9 ? seconds : "0" + seconds;
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
return days + " " + dHours + ":" + dMins + ":" + dSecs;
|
||||||
|
}
|
||||||
return dHours + ":" + dMins + ":" + dSecs;
|
return dHours + ":" + dMins + ":" + dSecs;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
35
webapp/src/components/partials/RadioInfo.vue
Normal file
35
webapp/src/components/partials/RadioInfo.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-white bg-primary">
|
||||||
|
Radio Information
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-condensed">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Chip Status</th>
|
||||||
|
<td class="badge" :class="{
|
||||||
|
'bg-danger': !radio_connected,
|
||||||
|
'bg-success': radio_connected,
|
||||||
|
}">
|
||||||
|
<span v-if="radio_connected">connected</span>
|
||||||
|
<span v-else>not connected</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
radio_connected: { type: Boolean, required: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
Loading…
Reference in New Issue
Block a user