diff --git a/BUILDS.md b/BUILDS.md
index d817ad3f7..ca97f2514 100644
--- a/BUILDS.md
+++ b/BUILDS.md
@@ -145,6 +145,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_PAJ7620 | - | - / - | - | - | - | - |
| USE_PCF8574 | - | - / - | - | - | - | - |
| USE_PMSA003I | - | - / - | - | - | - | - |
+| USE_LOX_O2 | - | - / x | - | x | - | - |
| | | | | | | |
| Feature or Sensor | l | t | k | s | i | d | Remarks
| USE_HIH6 | - | - / x | - | x | - | - |
diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md
index 40f7acc39..7d16b2b3b 100644
--- a/CODE_OWNERS.md
+++ b/CODE_OWNERS.md
@@ -203,6 +203,7 @@ In addition to @arendst the following code is mainly owned by:
| xsns_102_ld2410 | @arendst
| xsns_103_sen5x | @tyeth
| xsns_104_pmsa003i | Jean-Pierre Deschamps
+| xsns_105_lox_o2 | @ACE1046
| |
| Libraries |
| |
diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h
index d04f6ade5..559a7e236 100644
--- a/tasmota/include/tasmota_configurations.h
+++ b/tasmota/include/tasmota_configurations.h
@@ -250,6 +250,7 @@
#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code)
//#define USE_A4988_STEPPER // Add support for A4988/DRV8825 stepper-motor-driver-circuit (+10k5 code)
//#define USE_THERMOSTAT // Add support for Thermostat
+#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code)
#undef DEBUG_THEO // Disable debug code
#undef USE_DEBUG_DRIVER // Disable debug code
#endif // FIRMWARE_SENSORS
@@ -485,6 +486,7 @@
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
+#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor
#undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
@@ -618,6 +620,7 @@
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code)
#undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface
+#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor
#undef USE_ENERGY_SENSOR // Disable energy sensors
#undef USE_ADE7880 // Disable ADE7880 Energy monitor as used on Shelly 3EM (I2C address 0x38) (+3k8)
@@ -774,6 +777,7 @@
#undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8)
#undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code)
#undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+1k code)
+#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor
#undef USE_ENERGY_SENSOR // Disable energy sensors
#undef USE_PZEM004T // Disable PZEM004T energy sensor
@@ -931,6 +935,7 @@
#undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8)
#undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code)
#undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+0k6 code)
+#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor
#undef USE_ENERGY_SENSOR // Disable energy sensors
diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h
index 0ca277ffe..6accee7fc 100644
--- a/tasmota/include/tasmota_configurations_ESP32.h
+++ b/tasmota/include/tasmota_configurations_ESP32.h
@@ -138,6 +138,7 @@
#undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8)
#undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code)
#undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+0k6 code)
+#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor
#undef USE_ENERGY_SENSOR // Disable energy sensors
@@ -763,6 +764,7 @@
#define USE_BP1658CJ // Add support for BP1658CJ 5 channel led controller as used in Orein OS0100411267 Bulb
#define USE_ETHERNET // Add support for ethernet (+20k code)
#define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 display driver used by Sonoff POWR3xxD and THR3xxD
+#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code)
#ifndef USE_KNX
#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem)
diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h
index a85369d05..53570e3c9 100644
--- a/tasmota/include/tasmota_template.h
+++ b/tasmota/include/tasmota_template.h
@@ -208,6 +208,7 @@ enum UserSelectablePins {
GPIO_BIOPDU_PZEM0XX_TX, GPIO_BIOPDU_PZEM016_RX, GPIO_BIOPDU_BIT, // Biomine BioPDU 625x12
GPIO_MCP23XXX_INT, GPIO_MCP23SXX_CS, // MCP23xxx Int and SPI Chip select
GPIO_PCF8574_INT, // PCF8574 interrupt
+ GPIO_LOX_O2_RX, // LOX-O2 RX
GPIO_SENSOR_END };
// Error as warning to rethink GPIO usage with max 2045
@@ -463,6 +464,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BIOPDU_PZEM0XX_TX "|" D_SENSOR_BIOPDU_PZEM016_RX "|" D_SENSOR_BIOPDU_BIT "|"
D_SENSOR_MCP23XXX_INT "|" D_SENSOR_MCP23SXX_CS "|"
D_SENSOR_PCF8574_INT "|"
+ D_SENSOR_LOX_O2_RX "|"
;
const char kSensorNamesFixed[] PROGMEM =
@@ -1026,6 +1028,9 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_LD2410_TX), // HLK-LD2410 Serial interface
AGPIO(GPIO_LD2410_RX), // HLK-LD2410 Serial interface
#endif
+#ifdef USE_LOX_O2 // xsns_105_lox_o2.ino
+ AGPIO(GPIO_LOX_O2_RX), // LuminOx Oxygen Sensor LOX-O2 Serial interface
+#endif
/*-------------------------------------------------------------------------------------------*\
* Other sensors
diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h
index d43a80bf6..f588998c4 100644
--- a/tasmota/language/af_AF.h
+++ b/tasmota/language/af_AF.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h
index 97b7542a1..6aecade5e 100644
--- a/tasmota/language/bg_BG.h
+++ b/tasmota/language/bg_BG.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "А"
diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h
index 5191a364b..386d81141 100644
--- a/tasmota/language/ca_AD.h
+++ b/tasmota/language/ca_AD.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h
index a5ac51a55..4a9adf845 100644
--- a/tasmota/language/cs_CZ.h
+++ b/tasmota/language/cs_CZ.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h
index 6b635d872..5c57c51c1 100644
--- a/tasmota/language/de_DE.h
+++ b/tasmota/language/de_DE.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h
index 1b3cfc492..d4faa63d7 100644
--- a/tasmota/language/el_GR.h
+++ b/tasmota/language/el_GR.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h
index 8c54a340f..d603de544 100644
--- a/tasmota/language/en_GB.h
+++ b/tasmota/language/en_GB.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h
index 2948c9f05..6ca71b901 100644
--- a/tasmota/language/es_ES.h
+++ b/tasmota/language/es_ES.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h
index 7e1363747..58751d164 100644
--- a/tasmota/language/fr_FR.h
+++ b/tasmota/language/fr_FR.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h
index 6eb6e6c24..55a7c39d1 100644
--- a/tasmota/language/fy_NL.h
+++ b/tasmota/language/fy_NL.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h
index edf429bf6..07caf4f39 100644
--- a/tasmota/language/he_HE.h
+++ b/tasmota/language/he_HE.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h
index 80a9041ec..ad3a0c60e 100644
--- a/tasmota/language/hu_HU.h
+++ b/tasmota/language/hu_HU.h
@@ -931,6 +931,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h
index e77e208cd..239d077e1 100644
--- a/tasmota/language/it_IT.h
+++ b/tasmota/language/it_IT.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX - TX"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 - RX"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h
index 9e06ed6a5..365facce3 100644
--- a/tasmota/language/ko_KO.h
+++ b/tasmota/language/ko_KO.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h
index 542f3f04a..68920272e 100644
--- a/tasmota/language/nl_NL.h
+++ b/tasmota/language/nl_NL.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h
index 61621be08..0f7001baa 100644
--- a/tasmota/language/pl_PL.h
+++ b/tasmota/language/pl_PL.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h
index 453527b5e..11d615803 100644
--- a/tasmota/language/pt_BR.h
+++ b/tasmota/language/pt_BR.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h
index 732d3ef13..8d7ce12ef 100644
--- a/tasmota/language/pt_PT.h
+++ b/tasmota/language/pt_PT.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h
index e9611361a..a9300f72b 100644
--- a/tasmota/language/ro_RO.h
+++ b/tasmota/language/ro_RO.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h
index 29d8591b0..2ace1a9dc 100644
--- a/tasmota/language/ru_RU.h
+++ b/tasmota/language/ru_RU.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "А"
diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h
index f89cfd90d..bc5568259 100644
--- a/tasmota/language/sk_SK.h
+++ b/tasmota/language/sk_SK.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h
index 556335dcd..817255fae 100644
--- a/tasmota/language/sv_SE.h
+++ b/tasmota/language/sv_SE.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h
index e58e22682..df98b26cc 100644
--- a/tasmota/language/tr_TR.h
+++ b/tasmota/language/tr_TR.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h
index 6b5a3215f..54fb6e4f0 100644
--- a/tasmota/language/uk_UA.h
+++ b/tasmota/language/uk_UA.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "А"
diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h
index 06094ac7d..267a9d403 100644
--- a/tasmota/language/vi_VN.h
+++ b/tasmota/language/vi_VN.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h
index 36c35734c..624fa32b9 100644
--- a/tasmota/language/zh_CN.h
+++ b/tasmota/language/zh_CN.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "A"
diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h
index 764eff731..8b0433312 100644
--- a/tasmota/language/zh_TW.h
+++ b/tasmota/language/zh_TW.h
@@ -928,6 +928,7 @@
#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx"
#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx"
#define D_SENSOR_BIOPDU_BIT "BioPDU Bit"
+#define D_SENSOR_LOX_O2_RX "LoxO2 RX"
// Units
#define D_UNIT_AMPERE "安培"
diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h
index 97923feb9..ebc224061 100644
--- a/tasmota/my_user_config.h
+++ b/tasmota/my_user_config.h
@@ -822,6 +822,7 @@
// #define VINDRIKTNING_SHOW_PM1 // Display undocumented/supposed PM1.0 values
// #define VINDRIKTNING_SHOW_PM10 // Display undocumented/supposed PM10 values
//#define USE_LD2410 // Add support for HLK-LD2410 24GHz smart wave motion sensor (+2k8 code)
+// #define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code)
// -- Power monitoring sensors --------------------
#define USE_ENERGY_SENSOR // Add support for Energy Monitors (+14k code)
diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino
index 8a2ec6ba7..d889b4c69 100644
--- a/tasmota/tasmota_support/support_features.ino
+++ b/tasmota/tasmota_support/support_features.ino
@@ -882,7 +882,9 @@ void ResponseAppendFeatures(void)
#if defined(USE_I2C) && defined(USE_PMSA003I)
feature9 |= 0x00040000; // xsns_104_pmsa003i.ino
#endif
-// feature9 |= 0x00080000;
+#ifdef USE_LOX_O2
+ feature9 |= 0x00080000; // xsns_105_lox_o2.ino
+#endif
// feature9 |= 0x00100000;
// feature9 |= 0x00200000;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino b/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino
new file mode 100644
index 000000000..a644e964f
--- /dev/null
+++ b/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino
@@ -0,0 +1,156 @@
+/*
+ xsns_105_lox_o2.ino - Support for LuminOx Sealed Optical Oxygen Sensor on Tasmota
+
+ Copyright (C) 2023 Anton ACE Elizarov
+ https://github.com/ACE1046
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_LOX_O2
+/*********************************************************************************************\
+ * LuminOx Sealed Optical Oxygen Sensor LOX-02-S
+ *
+ * LuminOx requires no additional signal conditioning circuitry and connects
+ * directly to the interfacing microcontroller via a 3.3V-level USART link
+ * All USART communication is preformed using ascii characters
+ * By default, stream mode is initiated on sensor power-up and will supply an output string
+ * approximately once every second. This provides the data for ppO2, Temperature, Pressure, O2 and
+ * sensor status. Format is fixed, shown below:
+ * O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n
+ * i.e.
+ * O 0198.5 T +21.7 P 0983 % 020.19 e 0000\r\n
+\*********************************************************************************************/
+
+#define XSNS_105 105
+
+#define LOX_O2_BAUDRATE 9600
+
+#include
+TasmotaSerial *LOXSerial = nullptr;
+
+#define RESPONSE_LEN (sizeof("O 0198.5 T +21.7 P 0983 % 020.19 e 0000\r\n") - 1) // not including terminating zero
+
+struct LOX_O2
+{
+ float ppO2 = 0.0;
+ float temperature = 0.0;
+ uint32_t pressure = 0;
+ float O2 = 0.0;
+ uint32 error = 0;
+} *lox_o2 = nullptr;
+
+/********************************************************************************************/
+
+void LOXInit()
+{
+ if (PinUsed(GPIO_LOX_O2_RX))
+ {
+ lox_o2 = (LOX_O2 *)calloc(1, sizeof(struct LOX_O2));
+
+ LOXSerial = new TasmotaSerial(Pin(GPIO_LOX_O2_RX), -1, 1);
+ if (LOXSerial->begin(LOX_O2_BAUDRATE))
+ {
+ if (LOXSerial->hardwareSerial())
+ ClaimSerial();
+ }
+ }
+}
+
+void LOXParse(uint8_t *buf)
+{
+ if (!lox_o2) return;
+ // O 0198.5 T +21.7 P 0983 % 020.19 e 0000
+ if (buf[0] != 'O' || buf[9] != 'T' || buf[17] != 'P' || buf[24] != '%' || buf[33] != 'e') return; // check for valid response
+ lox_o2->pressure = strtoul((char *)buf+19, nullptr, 10);
+ lox_o2->ppO2 = CharToFloat((char *)buf+2);
+ lox_o2->temperature = CharToFloat((char *)buf+11);
+ lox_o2->O2 = CharToFloat((char *)buf+26);
+ lox_o2->error = strtoul((char *)buf+35, nullptr, 10);
+}
+
+void LOXJson()
+{
+ if (!lox_o2) return;
+ if (lox_o2->pressure > 0 && lox_o2->error == 0)
+ {
+ float temperature = ConvertTemp(lox_o2->temperature);
+ ResponseAppend_P(PSTR(",\"LOX\":{\"" D_JSON_PRESSURE "\":%i,\"ppO2\":%1_f,\"" D_JSON_TEMPERATURE "\":%1_f,\"" D_JSON_O2 "\":%2_f"),
+ lox_o2->pressure, &lox_o2->ppO2, &temperature, &lox_o2->O2);
+ ResponseJsonEnd();
+ }
+}
+
+void LOXRead()
+{
+ uint8_t buf[RESPONSE_LEN+1];
+ uint32_t in_buf = 0;
+
+ if (!LOXSerial || !lox_o2) return;
+
+ buf[RESPONSE_LEN] = 0;
+
+ while (LOXSerial->available() >= RESPONSE_LEN)
+ {
+ in_buf = 0;
+ while (LOXSerial->available() && in_buf < RESPONSE_LEN)
+ {
+ char c = LOXSerial->read();
+ buf[in_buf++] = c;
+ if (c == '\n') break;
+ }
+ if (in_buf == RESPONSE_LEN) LOXParse(buf);
+ }
+}
+
+#ifdef USE_WEBSERVER
+const char types[] = "LOX";
+void LOXShow(void)
+{
+ if (!LOXSerial || !lox_o2) return;
+ //AddLog(LOG_LEVEL_DEBUG, PSTR("LOX: %s"), value);
+ WSContentSend_PD(PSTR("{s}%s " D_PRESSURE "{m} %i " D_UNIT_PRESSURE "{e}"), types, lox_o2->pressure);
+ WSContentSend_PD(PSTR("{s}%s ppO2{m} %1_f " D_UNIT_PRESSURE "{e}"), types, &lox_o2->ppO2);
+ WSContentSend_Temp(types, ConvertTemp(lox_o2->temperature));
+ WSContentSend_PD(PSTR("{s}%s " D_O2 "{m} %2_f %%{e}"), types, &lox_o2->O2);
+}
+#endif // USE_WEBSERVER
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns105(uint32_t function) {
+ bool result = false;
+
+ switch (function) {
+ case FUNC_INIT:
+ LOXInit();
+ break;
+ case FUNC_EVERY_SECOND:
+ LOXRead();
+ break;
+ case FUNC_JSON_APPEND:
+ LOXJson();
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ LOXShow();
+ break;
+#endif // USE_WEBSERVER
+ }
+ return result;
+}
+
+#endif // USE_LOX
diff --git a/tools/decode-status.py b/tools/decode-status.py
index a0153d9b2..dca999845 100755
--- a/tools/decode-status.py
+++ b/tools/decode-status.py
@@ -293,7 +293,7 @@ a_features = [[
"USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ",
"USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007",
"USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X",
- "USE_BIOPDU","USE_MCP23XXX_DRV","USE_PMSA003I","",
+ "USE_BIOPDU","USE_MCP23XXX_DRV","USE_PMSA003I","USE_LOX_O2",
"","","","",
"","","","",
"","","",""
diff --git a/tools/lv_gpio/lv_gpio_enum.h b/tools/lv_gpio/lv_gpio_enum.h
index cfb7bdb92..0484e4490 100644
--- a/tools/lv_gpio/lv_gpio_enum.h
+++ b/tools/lv_gpio/lv_gpio_enum.h
@@ -332,5 +332,6 @@ ADE7953_CS = GPIO_ADE7953_CS
BIOPDU_PZEM0XX_TX = GPIO_BIOPDU_PZEM0XX_TX
BIOPDU_PZEM016_RX = GPIO_BIOPDU_PZEM016_RX
BIOPDU_BIT = GPIO_BIOPDU_BIT
+LOX_O2_RX = GPIO_LOX_O2_RX
SENSOR_END = GPIO_SENSOR_END