From fcc46327e11828ff57478855992f8ae59b74a9d0 Mon Sep 17 00:00:00 2001
From: nename0 <26363498+nename0@users.noreply.github.com>
Date: Sun, 7 Sep 2025 16:35:19 +0200
Subject: [PATCH 1/4] Usermod Temperature: use full 12-bit precision
---
usermods/Temperature/Temperature.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp
index a2e0ea91da..6df08ee9ac 100644
--- a/usermods/Temperature/Temperature.cpp
+++ b/usermods/Temperature/Temperature.cpp
@@ -20,7 +20,7 @@ float UsermodTemperature::readDallas() {
}
#endif
switch(sensorFound) {
- case 0x10: // DS18S20 has 9-bit precision
+ case 0x10: // DS18S20 has 9-bit precision - 1-bit fraction part
result = (data[1] << 8) | data[0];
retVal = float(result) * 0.5f;
break;
@@ -28,9 +28,9 @@ float UsermodTemperature::readDallas() {
case 0x28: // DS1822
case 0x3B: // DS1825
case 0x42: // DS28EA00
- result = (data[1]<<4) | (data[0]>>4); // we only need whole part, we will add fraction when returning
- if (data[1] & 0x80) result |= 0xF000; // fix negative value
- retVal = float(result) + ((data[0] & 0x08) ? 0.5f : 0.0f);
+ // 12-bit precision - 4-bit fraction part
+ result = (data[1] << 8) | data[0];
+ retVal = float(result) * 0.0625f; // 2^(-4)
break;
}
}
From 3017145196085733193168c5793da4f607593676 Mon Sep 17 00:00:00 2001
From: nename0 <26363498+nename0@users.noreply.github.com>
Date: Sun, 7 Sep 2025 16:57:35 +0200
Subject: [PATCH 2/4] Temperature Usermod: fix DS1822 and DS18B20 family code
---
usermods/Temperature/Temperature.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp
index 6df08ee9ac..a35c313582 100644
--- a/usermods/Temperature/Temperature.cpp
+++ b/usermods/Temperature/Temperature.cpp
@@ -24,8 +24,8 @@ float UsermodTemperature::readDallas() {
result = (data[1] << 8) | data[0];
retVal = float(result) * 0.5f;
break;
- case 0x22: // DS18B20
- case 0x28: // DS1822
+ case 0x22: // DS1822
+ case 0x28: // DS18B20
case 0x3B: // DS1825
case 0x42: // DS28EA00
// 12-bit precision - 4-bit fraction part
@@ -69,8 +69,8 @@ bool UsermodTemperature::findSensor() {
if (oneWire->crc8(deviceAddress, 7) == deviceAddress[7]) {
switch (deviceAddress[0]) {
case 0x10: // DS18S20
- case 0x22: // DS18B20
- case 0x28: // DS1822
+ case 0x22: // DS1822
+ case 0x28: // DS18B20
case 0x3B: // DS1825
case 0x42: // DS28EA00
DEBUG_PRINTLN(F("Sensor found."));
From 9056e5fd6de03a5f8d97bc804ec097b01d06d3fa Mon Sep 17 00:00:00 2001
From: nename0 <26363498+nename0@users.noreply.github.com>
Date: Sat, 13 Sep 2025 11:31:28 +0200
Subject: [PATCH 3/4] Add Dropdown to select 9 or 12 bit resolution
---
usermods/Temperature/Temperature.cpp | 33 +++++++++++++++--------
usermods/Temperature/UsermodTemperature.h | 2 ++
2 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp
index a35c313582..d0a0ab9440 100644
--- a/usermods/Temperature/Temperature.cpp
+++ b/usermods/Temperature/Temperature.cpp
@@ -31,6 +31,10 @@ float UsermodTemperature::readDallas() {
// 12-bit precision - 4-bit fraction part
result = (data[1] << 8) | data[0];
retVal = float(result) * 0.0625f; // 2^(-4)
+ if (!highResolution) {
+ result = retVal * 2.f;
+ retVal = float(result) * 0.5f;
+ }
break;
}
}
@@ -277,6 +281,7 @@ void UsermodTemperature::addToConfig(JsonObject &root) {
top[FPSTR(_parasite)] = parasite;
top[FPSTR(_parasitePin)] = parasitePin;
top[FPSTR(_domoticzIDX)] = idx;
+ top[FPSTR(_highResolution)] = highResolution;
DEBUG_PRINTLN(F("Temperature config saved."));
}
@@ -304,6 +309,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
parasite = top[FPSTR(_parasite)] | parasite;
parasitePin = top[FPSTR(_parasitePin)] | parasitePin;
idx = top[FPSTR(_domoticzIDX)] | idx;
+ highResolution = top[FPSTR(_highResolution)] | highResolution;
if (!initDone) {
// first run: reading from cfg.json
@@ -324,7 +330,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
}
}
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
- return !top[FPSTR(_domoticzIDX)].isNull();
+ return !top[FPSTR(_highResolution)].isNull();
}
void UsermodTemperature::appendConfigData() {
@@ -332,6 +338,10 @@ void UsermodTemperature::appendConfigData() {
oappend(F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field
+ oappend(F("dd=addDD('")); oappend(String(FPSTR(_name)).c_str());
+ oappend(F("','")); oappend(String(FPSTR(_highResolution)).c_str()); oappend(F("');"));
+ oappend(F("addO(dd,'0.5 °C (9-bit) resolution (legacy)',0);"));
+ oappend(F("addO(dd,'0.0625°C (12-bit) resolution',1);"));
}
float UsermodTemperature::getTemperature() {
@@ -345,16 +355,17 @@ const char *UsermodTemperature::getTemperatureUnit() {
UsermodTemperature* UsermodTemperature::_instance = nullptr;
// strings to reduce flash memory usage (used more than twice)
-const char UsermodTemperature::_name[] PROGMEM = "Temperature";
-const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
-const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
-const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
-const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
-const char UsermodTemperature::_domoticzIDX[] PROGMEM = "domoticz-idx";
-const char UsermodTemperature::_sensor[] PROGMEM = "sensor";
-const char UsermodTemperature::_temperature[] PROGMEM = "temperature";
-const char UsermodTemperature::_Temperature[] PROGMEM = "/temperature";
-const char UsermodTemperature::_data_fx[] PROGMEM = "Temperature@Min,Max;;!;01;pal=54,sx=255,ix=0";
+const char UsermodTemperature::_name[] PROGMEM = "Temperature";
+const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
+const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
+const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
+const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
+const char UsermodTemperature::_domoticzIDX[] PROGMEM = "domoticz-idx";
+const char UsermodTemperature::_highResolution[] PROGMEM = "high-resolution";
+const char UsermodTemperature::_sensor[] PROGMEM = "sensor";
+const char UsermodTemperature::_temperature[] PROGMEM = "temperature";
+const char UsermodTemperature::_Temperature[] PROGMEM = "/temperature";
+const char UsermodTemperature::_data_fx[] PROGMEM = "Temperature@Min,Max;;!;01;pal=54,sx=255,ix=0";
static uint16_t mode_temperature() {
float low = roundf(mapf((float)SEGMENT.speed, 0.f, 255.f, -150.f, 150.f)); // default: 15°C, range: -15°C to 15°C
diff --git a/usermods/Temperature/UsermodTemperature.h b/usermods/Temperature/UsermodTemperature.h
index 2517a2b817..a3de4bd3f6 100644
--- a/usermods/Temperature/UsermodTemperature.h
+++ b/usermods/Temperature/UsermodTemperature.h
@@ -48,6 +48,7 @@ class UsermodTemperature : public Usermod {
bool HApublished = false;
int16_t idx = -1; // Domoticz virtual sensor idx
+ int8_t highResolution = 0; // 0: 9-bit - 1: 12-bit
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
@@ -56,6 +57,7 @@ class UsermodTemperature : public Usermod {
static const char _parasite[];
static const char _parasitePin[];
static const char _domoticzIDX[];
+ static const char _highResolution[];
static const char _sensor[];
static const char _temperature[];
static const char _Temperature[];
From 020fde92b14eaa5f21e71725323e38e5c149f51f Mon Sep 17 00:00:00 2001
From: nename0 <26363498+nename0@users.noreply.github.com>
Date: Sat, 13 Sep 2025 20:00:43 +0200
Subject: [PATCH 4/4] Add 10 and 11 bit resolution, Correct rounding towards
negativ inf
---
usermods/Temperature/Temperature.cpp | 44 ++++++++++++-----------
usermods/Temperature/UsermodTemperature.h | 4 +--
2 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp
index d0a0ab9440..c86b9e9842 100644
--- a/usermods/Temperature/Temperature.cpp
+++ b/usermods/Temperature/Temperature.cpp
@@ -30,11 +30,9 @@ float UsermodTemperature::readDallas() {
case 0x42: // DS28EA00
// 12-bit precision - 4-bit fraction part
result = (data[1] << 8) | data[0];
+ // Clear LSBs to match desired precision (9/10/11-bit) rounding towards negative infinity
+ result &= 0xFFFF << (3 - (resolution & 3));
retVal = float(result) * 0.0625f; // 2^(-4)
- if (!highResolution) {
- result = retVal * 2.f;
- retVal = float(result) * 0.5f;
- }
break;
}
}
@@ -281,7 +279,7 @@ void UsermodTemperature::addToConfig(JsonObject &root) {
top[FPSTR(_parasite)] = parasite;
top[FPSTR(_parasitePin)] = parasitePin;
top[FPSTR(_domoticzIDX)] = idx;
- top[FPSTR(_highResolution)] = highResolution;
+ top[FPSTR(_resolution)] = resolution;
DEBUG_PRINTLN(F("Temperature config saved."));
}
@@ -309,7 +307,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
parasite = top[FPSTR(_parasite)] | parasite;
parasitePin = top[FPSTR(_parasitePin)] | parasitePin;
idx = top[FPSTR(_domoticzIDX)] | idx;
- highResolution = top[FPSTR(_highResolution)] | highResolution;
+ resolution = top[FPSTR(_resolution)] | resolution;
if (!initDone) {
// first run: reading from cfg.json
@@ -330,7 +328,7 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
}
}
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
- return !top[FPSTR(_highResolution)].isNull();
+ return !top[FPSTR(_resolution)].isNull();
}
void UsermodTemperature::appendConfigData() {
@@ -339,9 +337,13 @@ void UsermodTemperature::appendConfigData() {
oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str());
oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field
oappend(F("dd=addDD('")); oappend(String(FPSTR(_name)).c_str());
- oappend(F("','")); oappend(String(FPSTR(_highResolution)).c_str()); oappend(F("');"));
- oappend(F("addO(dd,'0.5 °C (9-bit) resolution (legacy)',0);"));
- oappend(F("addO(dd,'0.0625°C (12-bit) resolution',1);"));
+ oappend(F("','")); oappend(String(FPSTR(_resolution)).c_str()); oappend(F("');"));
+ oappend(F("addO(dd,'0.5 °C (9-bit)',0);"));
+ oappend(F("addO(dd,'0.25°C (10-bit)',1);"));
+ oappend(F("addO(dd,'0.125°C (11-bit)',2);"));
+ oappend(F("addO(dd,'0.0625°C (12-bit)',3);"));
+ oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_resolution)).c_str());
+ oappend(F("',1,'(ignored on DS18S20)');")); // 0 is field type, 1 is actual field
}
float UsermodTemperature::getTemperature() {
@@ -355,17 +357,17 @@ const char *UsermodTemperature::getTemperatureUnit() {
UsermodTemperature* UsermodTemperature::_instance = nullptr;
// strings to reduce flash memory usage (used more than twice)
-const char UsermodTemperature::_name[] PROGMEM = "Temperature";
-const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
-const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
-const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
-const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
-const char UsermodTemperature::_domoticzIDX[] PROGMEM = "domoticz-idx";
-const char UsermodTemperature::_highResolution[] PROGMEM = "high-resolution";
-const char UsermodTemperature::_sensor[] PROGMEM = "sensor";
-const char UsermodTemperature::_temperature[] PROGMEM = "temperature";
-const char UsermodTemperature::_Temperature[] PROGMEM = "/temperature";
-const char UsermodTemperature::_data_fx[] PROGMEM = "Temperature@Min,Max;;!;01;pal=54,sx=255,ix=0";
+const char UsermodTemperature::_name[] PROGMEM = "Temperature";
+const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
+const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
+const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";
+const char UsermodTemperature::_parasitePin[] PROGMEM = "parasite-pwr-pin";
+const char UsermodTemperature::_domoticzIDX[] PROGMEM = "domoticz-idx";
+const char UsermodTemperature::_resolution[] PROGMEM = "resolution";
+const char UsermodTemperature::_sensor[] PROGMEM = "sensor";
+const char UsermodTemperature::_temperature[] PROGMEM = "temperature";
+const char UsermodTemperature::_Temperature[] PROGMEM = "/temperature";
+const char UsermodTemperature::_data_fx[] PROGMEM = "Temperature@Min,Max;;!;01;pal=54,sx=255,ix=0";
static uint16_t mode_temperature() {
float low = roundf(mapf((float)SEGMENT.speed, 0.f, 255.f, -150.f, 150.f)); // default: 15°C, range: -15°C to 15°C
diff --git a/usermods/Temperature/UsermodTemperature.h b/usermods/Temperature/UsermodTemperature.h
index a3de4bd3f6..555b57cf7a 100644
--- a/usermods/Temperature/UsermodTemperature.h
+++ b/usermods/Temperature/UsermodTemperature.h
@@ -48,7 +48,7 @@ class UsermodTemperature : public Usermod {
bool HApublished = false;
int16_t idx = -1; // Domoticz virtual sensor idx
- int8_t highResolution = 0; // 0: 9-bit - 1: 12-bit
+ uint8_t resolution = 0; // 9bits=0, 10bits=1, 11bits=2, 12bits=3
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
@@ -57,7 +57,7 @@ class UsermodTemperature : public Usermod {
static const char _parasite[];
static const char _parasitePin[];
static const char _domoticzIDX[];
- static const char _highResolution[];
+ static const char _resolution[];
static const char _sensor[];
static const char _temperature[];
static const char _Temperature[];