Compare commits

..

1 Commits

Author SHA1 Message Date
CaCO3
74e150cfab clarify the parameter prefix 2025-04-22 23:58:44 +02:00
12 changed files with 54 additions and 157 deletions

View File

@@ -1,28 +1,4 @@
# [16.1.0-RC1] - 2025-12-29 # [16.0.0] - 2024-03-15
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v16.0.0...v16.1.0)
### Known issues
No software is perfect. We know that our software has some quirks. If you have an issue, please first check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
### Core Changes and Bug fixes
- Various minor improvements and changes
- Various documentation corrections/improvements
- Parameter `ChangeRateThreshold` can now also be zero [#3668](https://github.com/jomjol/AI-on-the-edge-device/pull/3668)
- MQTT: Added a proper `device_class` (duration) to "uptime" [#3659](https://github.com/jomjol/AI-on-the-edge-device/pull/3659)
- MQTT: Added `default_entity_id` to MQTT HA autodiscovery payload [#3970](https://github.com/jomjol/AI-on-the-edge-device/pull/3970)
- Added new models
- Updated SDCard Manufacturer List [#3730](https://github.com/jomjol/AI-on-the-edge-device/pull/3730)
- Added option for gal/min rate for Home Assistant MQTT Autodiscovery[#3868](https://github.com/jomjol/AI-on-the-edge-device/pull/3868)
- Fixed Setup Wizard [#3906](https://github.com/jomjol/AI-on-the-edge-device/pull/3906)
- `checkDigitConsistency`: added ESP_LOG_DEBUG output [#3962](https://github.com/jomjol/AI-on-the-edge-device/pull/3962)
- Added "Draw from center" option to Analog ROI editor [#3975](https://github.com/jomjol/AI-on-the-edge-device/pull/3975)
- Enabled OV3660 support in sdkconfig.defaults [#3996](https://github.com/jomjol/AI-on-the-edge-device/pull/3996)
# [16.0.0] - 2025-03-15
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0) For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0)

View File

@@ -166,7 +166,6 @@ Various 3D-printable housings can be found here:
- ⚡ [Power Meter](https://www.thingiverse.com/thing:5028229) - ⚡ [Power Meter](https://www.thingiverse.com/thing:5028229)
- 🔥 [Gas Meter](https://www.thingiverse.com/thing:5224101) - 🔥 [Gas Meter](https://www.thingiverse.com/thing:5224101)
- 📷 [ESP32-cam housing only](https://www.thingiverse.com/thing:4571627) - 📷 [ESP32-cam housing only](https://www.thingiverse.com/thing:4571627)
- 📡 [Top cover and Antenna Holder](https://www.printables.com/model/452139-cover-for-esp32-cam-water-meter)
--- ---

View File

@@ -161,9 +161,6 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
else if (toUpper(splitted[1]) == "WATER_GAL") { else if (toUpper(splitted[1]) == "WATER_GAL") {
mqttServer_setMeterType("water", "gal", "h", "gal/h"); mqttServer_setMeterType("water", "gal", "h", "gal/h");
} }
else if (toUpper(splitted[1]) == "WATER_GAL_MIN") {
mqttServer_setMeterType("water", "gal", "min", "gal/min"); // min = Minutes
}
else if (toUpper(splitted[1]) == "GAS_M3") { else if (toUpper(splitted[1]) == "GAS_M3") {
mqttServer_setMeterType("gas", "", "h", "m³/h"); mqttServer_setMeterType("gas", "", "h", "m³/h");
} }

View File

@@ -758,8 +758,17 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift) {
} }
bool ClassFlowPostProcessing::doFlow(string zwtime) { bool ClassFlowPostProcessing::doFlow(string zwtime) {
string result = "";
string digit = "";
string analog = "";
string zwvalue; string zwvalue;
time_t imagetime = flowTakeImage->getTimeImageTaken(); string zw;
time_t imagetime = 0;
string rohwert;
// Update decimal point, as the decimal places can also change when changing from CNNType Auto --> xyz:
imagetime = flowTakeImage->getTimeImageTaken();
if (imagetime == 0) { if (imagetime == 0) {
time(&imagetime); time(&imagetime);
@@ -785,7 +794,6 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) {
// double LastValueTimeDifference = difftime(imagetime, NUMBERS[j]->timeStampLastValue); // in seconds // double LastValueTimeDifference = difftime(imagetime, NUMBERS[j]->timeStampLastValue); // in seconds
double LastPreValueTimeDifference = difftime(imagetime, NUMBERS[j]->timeStampLastPreValue); // in seconds double LastPreValueTimeDifference = difftime(imagetime, NUMBERS[j]->timeStampLastPreValue); // in seconds
// Update decimal point, as the decimal places can also change when changing from CNNType Auto --> xyz:
UpdateNachkommaDecimalShift(); UpdateNachkommaDecimalShift();
int previous_value = -1; int previous_value = -1;
@@ -876,15 +884,12 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) {
if (NUMBERS[j]->checkDigitIncreaseConsistency) { if (NUMBERS[j]->checkDigitIncreaseConsistency) {
if (flowDigit) { if (flowDigit) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Before checkDigitConsistency: value=" + std::to_string(NUMBERS[j]->Value));
NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue); NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "After checkDigitConsistency: value=" + std::to_string(NUMBERS[j]->Value));
} }
else { else {
#ifdef SERIAL_DEBUG #ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - no digit numbers defined!"); ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - no digit numbers defined!");
#endif #endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "checkDigitIncreaseConsistency = true - no digit numbers defined!");
} }
} }
@@ -1123,7 +1128,6 @@ float ClassFlowPostProcessing::checkDigitConsistency(double input, int _decilams
#ifdef SERIAL_DEBUG #ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "checkDigitConsistency: pot=%d, decimalshift=%d", pot, _decilamshift); ESP_LOGD(TAG, "checkDigitConsistency: pot=%d, decimalshift=%d", pot, _decilamshift);
#endif #endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "checkDigitConsistency: pot=" + std::to_string(pot) + ", decimalshift=" + std::to_string(_decilamshift));
pot_max = ((int) log10(input)) + 1; pot_max = ((int) log10(input)) + 1;
@@ -1155,7 +1159,6 @@ float ClassFlowPostProcessing::checkDigitConsistency(double input, int _decilams
#ifdef SERIAL_DEBUG #ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "checkDigitConsistency: input=%f", input); ESP_LOGD(TAG, "checkDigitConsistency: input=%f", input);
#endif #endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "checkDigitConsistency: input=" + std::to_string(input));
pot++; pot++;
} }

View File

@@ -806,21 +806,11 @@ struct SDCard_Manufacturer_database sd_database[] = {
.id = 0x03, .id = 0x03,
.manufacturer = "SanDisk", .manufacturer = "SanDisk",
}, },
{
.type = "sd",
.id = 0x05,
.manufacturer = "Lenovo",
},
{ {
.type = "sd", .type = "sd",
.id = 0x08, .id = 0x08,
.manufacturer = "Silicon Power", .manufacturer = "Silicon Power",
}, },
{
.type = "sd",
.id = 0x09,
.manufacturer = "ATP",
},
{ {
.type = "sd", .type = "sd",
.id = 0x18, .id = 0x18,
@@ -904,27 +894,7 @@ struct SDCard_Manufacturer_database sd_database[] = {
{ {
.type = "sd", .type = "sd",
.id = 0x89, .id = 0x89,
.manufacturer = "Netac", .manufacturer = "Unknown",
},
{
.type = "sd",
.id = 0x9f,
.manufacturer = "Kingston/Kodak/Silicon Power",
},
{
.type = "sd",
.id = 0xad,
.manufacturer = "Amazon Basics/Lexar/OV",
},
{
.type = "sd",
.id = 0xdf,
.manufacturer = "Lenovo",
},
{
.type = "sd",
.id = 0xfe,
.manufacturer = "Bekit/Cloudisk/HP/Reletech",
}, },
}; };
@@ -1248,7 +1218,7 @@ bool replaceString(std::string &s, std::string const &toReplace, std::string con
if (logIt) if (logIt)
{ {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line '" + old + "' to '" + s + "'");
} }
return true; return true;

View File

@@ -72,7 +72,6 @@ bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
std::string topicFull; std::string topicFull;
std::string configTopic; std::string configTopic;
std::string payload; std::string payload;
std::string component;
configTopic = field; configTopic = field;
@@ -81,16 +80,6 @@ bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
name = group + " " + name; name = group + " " + name;
} }
if (field == "problem") { // Special case: Binary sensor which is based on error topic
component = "binary_sensor";
}
else if (field == "flowstart") { // Special case: Button
component = "button";
}
else {
component = "sensor";
}
/** /**
* homeassistant needs the MQTT discovery topic according to the following structure: * homeassistant needs the MQTT discovery topic according to the following structure:
* <discovery_prefix>/<component>/[<node_id>/]<object_id>/config * <discovery_prefix>/<component>/[<node_id>/]<object_id>/config
@@ -98,14 +87,21 @@ bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
* This means a maintopic "home/test/watermeter" is transformed to the discovery topic "homeassistant/sensor/watermeter/..." * This means a maintopic "home/test/watermeter" is transformed to the discovery topic "homeassistant/sensor/watermeter/..."
*/ */
std::string node_id = createNodeId(maintopic); std::string node_id = createNodeId(maintopic);
topicFull = "homeassistant/" + component + "/" + node_id + "/" + configTopic + "/config"; if (field == "problem") { // Special case: Binary sensor which is based on error topic
topicFull = "homeassistant/binary_sensor/" + node_id + "/" + configTopic + "/config";
}
else if (field == "flowstart") { // Special case: Button
topicFull = "homeassistant/button/" + node_id + "/" + configTopic + "/config";
}
else {
topicFull = "homeassistant/sensor/" + node_id + "/" + configTopic + "/config";
}
/* See https://www.home-assistant.io/docs/mqtt/discovery/ */ /* See https://www.home-assistant.io/docs/mqtt/discovery/ */
payload = string("{") + payload = string("{") +
"\"~\": \"" + maintopic + "\"," + "\"~\": \"" + maintopic + "\"," +
"\"unique_id\": \"" + maintopic + "-" + configTopic + "\"," + "\"unique_id\": \"" + maintopic + "-" + configTopic + "\"," +
"\"object_id\": \"" + maintopic + "_" + configTopic + "\"," + // Default entity ID; required for HA <= 2025.10 "\"object_id\": \"" + maintopic + "_" + configTopic + "\"," + // This used to generate the Entity ID
"\"default_entity_id\": \"" + component + "." + maintopic + "_" + configTopic + "\"," + // Default entity ID; required in HA >=2026.4
"\"name\": \"" + name + "\"," + "\"name\": \"" + name + "\"," +
"\"icon\": \"mdi:" + icon + "\","; "\"icon\": \"mdi:" + icon + "\",";

View File

@@ -635,7 +635,7 @@ void migrateConfiguration(void) {
CamZoom_value = false; CamZoom_value = false;
} }
else { else {
// ESP_LOGI(TAG, "splitted[1]: %s", splitted[1].c_str()); ESP_LOGE(TAG, "splitted[1]: %s", splitted[1].c_str());
CamZoom_value = alphanumericToBoolean(splitted[1]); CamZoom_value = alphanumericToBoolean(splitted[1]);
} }
CamZoom_found = true; CamZoom_found = true;
@@ -858,22 +858,22 @@ void migrateConfiguration(void) {
else { else {
configLines[CamZoom_lines] = ("CamZoom = false"); configLines[CamZoom_lines] = ("CamZoom = false");
} }
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Migrated Configfile line 'Zoom' to 'CamZoom'"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'Zoom' to 'CamZoom'");
migrated = true; migrated = true;
} }
if (CamZoomSize_lines > 0) { if (CamZoomSize_lines > 0) {
configLines[CamZoomSize_lines] = ("CamZoomSize = " + std::to_string(CamZoomSize_value)); configLines[CamZoomSize_lines] = ("CamZoomSize = " + std::to_string(CamZoomSize_value));
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Migrated Configfile line 'ZoomMode' to 'CamZoomSize'"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomMode' to 'CamZoomSize'");
migrated = true; migrated = true;
} }
if (CamZoomOffsetX_lines > 0) { if (CamZoomOffsetX_lines > 0) {
configLines[CamZoomOffsetX_lines] = ("CamZoomOffsetX = " + std::to_string(CamZoomOffsetX_value)); configLines[CamZoomOffsetX_lines] = ("CamZoomOffsetX = " + std::to_string(CamZoomOffsetX_value));
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Migrated Configfile line 'ZoomOffsetX' to 'CamZoomOffsetX'"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetX' to 'CamZoomOffsetX'");
migrated = true; migrated = true;
} }
if (CamZoomOffsetY_lines > 0) { if (CamZoomOffsetY_lines > 0) {
configLines[CamZoomOffsetY_lines] = ("CamZoomOffsetY = " + std::to_string(CamZoomOffsetY_value)); configLines[CamZoomOffsetY_lines] = ("CamZoomOffsetY = " + std::to_string(CamZoomOffsetY_value));
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Migrated Configfile line 'ZoomOffsetY' to 'CamZoomOffsetY'"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetY' to 'CamZoomOffsetY'");
migrated = true; migrated = true;
} }
} }

View File

@@ -158,7 +158,7 @@ CONFIG_CAMERA_CORE1=y
CONFIG_OV7670_SUPPORT=n CONFIG_OV7670_SUPPORT=n
CONFIG_OV7725_SUPPORT=n CONFIG_OV7725_SUPPORT=n
CONFIG_NT99141_SUPPORT=n CONFIG_NT99141_SUPPORT=n
CONFIG_OV3660_SUPPORT=y CONFIG_OV3660_SUPPORT=n
CONFIG_OV2640_SUPPORT=y CONFIG_OV2640_SUPPORT=y
CONFIG_OV5640_SUPPORT=y CONFIG_OV5640_SUPPORT=y
CONFIG_GC2145_SUPPORT=n CONFIG_GC2145_SUPPORT=n

View File

@@ -11,22 +11,18 @@ List of supported options:
- `other` - `other`
- `water_m3` (uses `m^3/h` as rate) - `water_m3` (uses `m^3/h` as rate)
- `water_l` (uses `l/h` as rate) **⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️** - `water_l` (uses `l/h` as rate, not officially supported by Homeassistant!)
- `water_gal` (uses `gal/h` as rate) **⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️** - `water_gal` (uses `gal/h` as rate, not officially supported by Homeassistant!)
- `water_gal_min` (uses `gal/min` as rate)
- `water_ft3` (uses `ft^3/min` as rate) - `water_ft3` (uses `ft^3/min` as rate)
- `gas_m3` (uses `m^3/h` as rate) - `gas_m3` (uses `m^3/h` as rate)
- `gas_ft3` (uses `ft^3/min` as rate) - `gas_ft3` (uses `ft^3/min` as rate)
- `energy_wh` (uses `W` as rate) - `energy_wh` (uses `W` as rate)
- `energy_kwh` (uses `KW` as rate) - `energy_kwh` (uses `KW` as rate)
- `energy_mwh` (uses `MW` as rate) - `energy_mwh` (uses `MW` as rate)
- `energy_gj` (uses `GJ/h` as rate) **⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️** - `energy_gj` (uses `GJ/h` as rate, not officially supported by Homeassistant!)
- `temperature_c` (uses `+C/min` as rate) - `temperature_c` (uses `+C/min` as rate)
- `temperature_f` (uses `°F/min` as rate) - `temperature_f` (uses `°F/min` as rate)
- `temperature_k` (uses `K/min` as rate) - `temperature_k` (uses `K/min` as rate)
!!! Note !!! Note
Not all options are supported by Homeassistant, see `SensorDeviceClass.VOLUME_FLOW_RATE` in [https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes)! Not all options are supported by Homeassistant, see `SensorDeviceClass.VOLUME_FLOW_RATE` in [https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes)!
!!! Warning
Since Homeassistant 2025.7, the unsupported options will no longer work, see change in Homeassistant: [Ensure MQTT sensor has a valid native unit of measurement](https://github.com/home-assistant/core/pull/146722).

View File

@@ -156,7 +156,6 @@ The following settings are only used for easier setup, they are <b>not</b> persi
<input type="checkbox" id="showall" name="showall" value="1" onclick="draw()" checked tabindex=9><label for="showall"> Show all ROIs</label><br> <input type="checkbox" id="showall" name="showall" value="1" onclick="draw()" checked tabindex=9><label for="showall"> Show all ROIs</label><br>
<input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label><br> <input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label><br>
<input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label><br> <input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label><br>
<input type="checkbox" id="drawFromCenter" name="drawFromCenter" value="1" onclick="changeDrawFromCenter()" checked tabindex=8><label for="drawFromCenter"> Draw from center</label><br>
<hr> <hr>
<table> <table>
@@ -197,7 +196,6 @@ The following settings are only used for easier setup, they are <b>not</b> persi
enhanceCon = false, enhanceCon = false,
lockAspectRatio = true, lockAspectRatio = true,
lockSizes = false, lockSizes = false,
drawFromCenter = true,
domainname = getDomainname(); domainname = getDomainname();
function doReboot() { function doReboot() {
@@ -321,10 +319,6 @@ The following settings are only used for easier setup, they are <b>not</b> persi
UpdateROIs(); UpdateROIs();
} }
function changeDrawFromCenter() {
drawFromCenter = document.getElementById("drawFromCenter").checked;
}
function changeCCW() { function changeCCW() {
var sel = document.getElementById("Numbers_value1"); var sel = document.getElementById("Numbers_value1");
var _number = sel.options[sel.selectedIndex].text; var _number = sel.options[sel.selectedIndex].text;
@@ -806,10 +800,6 @@ The following settings are only used for easier setup, they are <b>not</b> persi
zw = getCoords(this) zw = getCoords(this)
rect.startX = e.pageX - zw.left; rect.startX = e.pageX - zw.left;
rect.startY = e.pageY - zw.top; rect.startY = e.pageY - zw.top;
if (drawFromCenter) {
rect.centerX = rect.startX;
rect.centerY = rect.startY;
}
document.getElementById("refx").value = rect.startX; document.getElementById("refx").value = rect.startX;
document.getElementById("refy").value = rect.startY; document.getElementById("refy").value = rect.startY;
drag = true; drag = true;
@@ -832,33 +822,16 @@ The following settings are only used for easier setup, they are <b>not</b> persi
} }
function mouseMove(e) { function mouseMove(e) {
const mouseX = e.pageX - zw.left;
const mouseY = e.pageY - zw.top;
if (drag) { if (drag) {
zw = getCoords(this) zw = getCoords(this)
if (drawFromCenter) {
if (lockAspectRatio) { if (lockAspectRatio) {
rect.h = Math.abs(mouseY - rect.centerY) * 2; rect.h = (e.pageY - zw.top) - rect.startY;
rect.w = Math.round(rect.h * ROIInfo[aktindex]["ar"]); rect.w = Math.round(rect.h * ROIInfo[aktindex]["ar"]);
} else {
rect.w = Math.abs(mouseX - rect.centerX) * 2;
rect.h = Math.abs(mouseY - rect.centerY) * 2;
}
rect.startX = rect.centerX - rect.w / 2;
rect.startY = rect.centerY - rect.h / 2;
document.getElementById("refx").value = Math.round(rect.startX);
document.getElementById("refy").value = Math.round(rect.startY);
} else {
if (lockAspectRatio) {
rect.h = mouseY - rect.startY;
rect.w = Math.round(rect.h * ROIInfo[aktindex]["ar"]);
} else {
rect.w = mouseX - rect.startX;
rect.h = mouseY - rect.startY;
} }
else {
rect.w = (e.pageX - zw.left) - rect.startX;
rect.h = (e.pageY - zw.top) - rect.startY;
} }
document.getElementById("refdx").value = rect.w; document.getElementById("refdx").value = rect.w;
document.getElementById("refdy").value = rect.h; document.getElementById("refdy").value = rect.h;
@@ -870,8 +843,8 @@ The following settings are only used for easier setup, they are <b>not</b> persi
var context = canvas.getContext('2d'); var context = canvas.getContext('2d');
zw = getCoords(this); zw = getCoords(this);
x = mouseX; x = e.pageX - zw.left;
y = mouseY; y = e.pageY - zw.top;
context.lineWidth = 2; context.lineWidth = 2;
context.strokeStyle = "#00FF00"; context.strokeStyle = "#00FF00";

View File

@@ -1183,16 +1183,15 @@
<select class="select_large" id="MQTT_MeterType_value1"> <!-- See https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes --> <select class="select_large" id="MQTT_MeterType_value1"> <!-- See https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes -->
<option value="other" selected>Other (no Units)</option> <option value="other" selected>Other (no Units)</option>
<option value="water_m3">Watermeter (Value: m³, Rate: m³/h)</option> <option value="water_m3">Watermeter (Value: m³, Rate: m³/h)</option>
<option value="water_l">Watermeter (Value: l, Rate: l/h) ⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️</option> <option value="water_l">Watermeter (Value: l, Rate: l/h) *Not officially supported by Homeassistant!*</option>
<option value="water_gal">Watermeter (Value: gal, Rate: gal/h) ⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️</option> <option value="water_gal">Watermeter (Value: gal, Rate: gal/h) *Not officially supported by Homeassistant!*</option>
<option value="water_gal_min">Watermeter (Value: gal, Rate: gal/min)</option>
<option value="water_ft3">Watermeter (Value: ft³, Rate: ft³/min)</option> <option value="water_ft3">Watermeter (Value: ft³, Rate: ft³/min)</option>
<option value="gas_m3">Gasmeter (Value: m³, Rate: m³/h)</option> <option value="gas_m3">Gasmeter (Value: m³, Rate: m³/h)</option>
<option value="gas_ft3">Gasmeter (Value: ft³, Rate: ft³/min)</option> <option value="gas_ft3">Gasmeter (Value: ft³, Rate: ft³/min)</option>
<option value="energy_wh">Energymeter (Value: Wh, Rate: W)</option> <option value="energy_wh">Energymeter (Value: Wh, Rate: W)</option>
<option value="energy_kwh">Energymeter (Value: kWh, Rate: kW)</option> <option value="energy_kwh">Energymeter (Value: kWh, Rate: kW)</option>
<option value="energy_mwh">Energymeter (Value: MWh, Rate: MW)</option> <option value="energy_mwh">Energymeter (Value: MWh, Rate: MW)</option>
<option value="energy_gj">Energymeter (Value: GJ, Rate: GJ/h) ⚠️ Not supported by Homeassistant 2025.7 and later! ⚠️</option> <option value="energy_gj">Energymeter (Value: GJ, Rate: GJ/h) *Not officially supported by Homeassistant!*</option>
<option value="temperature_c">Thermometer (Value: °C, Rate: °C/min)</option> <option value="temperature_c">Thermometer (Value: °C, Rate: °C/min)</option>
<option value="temperature_c">Thermometer (Value: °F, Rate: °F/min)</option> <option value="temperature_c">Thermometer (Value: °F, Rate: °F/min)</option>
<option value="temperature_c">Thermometer (Value: K, Rate: K/min)</option> <option value="temperature_c">Thermometer (Value: K, Rate: K/min)</option>
@@ -2677,19 +2676,7 @@ function saveTextAsFile() {
WriteConfigININew(); WriteConfigININew();
SaveConfigToServer(domainname); SaveConfigToServer(domainname);
if(window.location.hash) {
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
if(hash == 'description') {
firework.launch('Configuration saved.', 'success', 2000);
}
else {
firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000); firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
}
}
else {
firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
}
if (changeCamValue == 1) { if (changeCamValue == 1) {
camSettingsSet(); camSettingsSet();
@@ -3344,7 +3331,7 @@ function openDescription() {
if(hash == 'description') { if(hash == 'description') {
document.getElementById("desc_details").open = true; document.getElementById("desc_details").open = true;
// document.getElementById("reboot").style.display = "none"; document.getElementById("reboot").style.display = "none";
document.getElementById("reboot_text").style.display = "none"; document.getElementById("reboot_text").style.display = "none";
} }
} }