mirror of
https://github.com/arendst/Tasmota.git
synced 2026-10-26 22:11:22 +00:00
Matter Soil Sensor device type with Soil Measurement cluster (Matter 1.6.0) (#25088)
This commit is contained in:
1 parent
1f543a3374
commit
a242811ec8
9 files changed
+275
-7
No files matched your search
@@ -225,7 +225,12 @@ The following changes are part of Matter 1.6.1 (released September 2026, PR #735
|
||||
- Commodity Tariff cluster (0x0700) read implementation
|
||||
- Device Energy Management cluster (0x0098) for power measurement + demand response hints
|
||||
- **Timeframe:** 3-4 weeks
|
||||
- **Integration:** Extend existing power sensor plugins; enable smart scheduling based on tariff
|
||||
|
||||
### Phase 2b: Tariff & Price (deferred)
|
||||
- Commodity Price (0x0095, Rev 4) and Commodity Tariff (0x0700, Rev 1)
|
||||
- **Why deferred:** per the Device Library, both clusters are only hosted by the Electrical Energy Tariff device type (0x0513), which must be a child of a Meter Reference Point (0x0512) endpoint with Identify, and must carry Descriptor TagList semantic tags (Commodity Tariff Commodity/Chronology namespaces, plus Grid/Import/AC in the basic topology). The Root Node also needs the TimeSyncCond condition. Commodity Tariff alone carries 14+ attributes with deeply nested structs.
|
||||
- **Prerequisites:** Namespace Specification 1.6 (to confirm namespace/tag IDs), a parent/child virtual composition (PartsList override, as in `Matter_Plugin_9_Virt_HVAC.be`), Descriptor TagList support (FeatureMap bit 0 on 0x001D)
|
||||
- **Data source:** none native in Tasmota; values would be pushed via `MtrUpdate` (rules/scripts/MQTT)
|
||||
|
||||
### Phase 3: Closures Unified Architecture (v1.6.0, medium-value features)
|
||||
- Closure device type (0x0230) with Closure Control (0x0104) and Closure Dimension (0x0105) clusters
|
||||
@@ -240,6 +245,8 @@ The following changes are part of Matter 1.6.1 (released September 2026, PR #735
|
||||
- **Timeframe:** 1 week
|
||||
- **Integration:** Extends existing humidity/temperature sensor plugins
|
||||
|
||||
- Doorbell device type (0x0148) — optional, can defer to maintenance release
|
||||
|
||||
### Phase 5: Validation & Compliance Testing (v1.6.0)
|
||||
- Multi-controller interoperability (Apple Home, Google Home, Alexa, SmartThings, Home Assistant)
|
||||
- DataModelRevision = 20 verification
|
||||
|
||||
@@ -342,7 +342,7 @@ The Tasmota Matter implementation is currently aligned with **Matter 1.4.1** (Da
|
||||
| **DataModelRevision** | 18 | 20 | ⚠️ Not updated | <1 day |
|
||||
| **Closures clusters** | Window Covering (legacy) | Closure Control/Dimension (new) | ❌ Missing | 2 weeks |
|
||||
| **Energy Management** | 0x0090/0x0091 only | Add Commodity Price/Tariff, Device EM, EVSE | ❌ Missing | 3-4 weeks |
|
||||
| **Soil Measurement** | None | Soil Sensor (0x0045) + cluster | ❌ Missing | 1 week |
|
||||
| **Soil Measurement** | None | Soil Sensor (0x0045) + cluster | ✅ Done | — |
|
||||
| **Doorbell** | None | 0x0148/0x0141/0x0143 | ❌ Missing | 1 week |
|
||||
| **Access Control** | Partial | Complete read + rev updates | ⚠️ Partial | 3-5 days |
|
||||
| **Group Key Management** | Rev 2 | Rev 4 | ⚠️ Outdated | 1 week |
|
||||
|
||||
@@ -240,6 +240,8 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
|
||||
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Illuminance.h"
|
||||
#include "solidify/solidified_Matter_Plugin_3_Sensor_Humidity.h"
|
||||
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Humidity.h"
|
||||
#include "solidify/solidified_Matter_Plugin_3_Sensor_Soil.h"
|
||||
#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Soil.h"
|
||||
#include "solidify/solidified_Matter_Plugin_2_Sensor_Boolean.h"
|
||||
#include "solidify/solidified_Matter_Plugin_3_Sensor_Occupancy.h"
|
||||
#include "solidify/solidified_Matter_Plugin_3_Sensor_OnOff.h"
|
||||
@@ -266,6 +268,7 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Temp.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Illuminance.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Humidity.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Soil.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Occupancy.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Contact.h"
|
||||
#include "solidify/solidified_Matter_Plugin_8_Bridge_Sensor_Flow.h"
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
#
|
||||
# Matter_Plugin_Sensor_Soil.be - implements the behavior for a Soil Sensor
|
||||
#
|
||||
# Copyright (C) 2026 Ludovic BOUÉ
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#################################################################################
|
||||
# Matter 1.6.0 Device Specification
|
||||
#################################################################################
|
||||
# Device Type: Soil Sensor (0x0045)
|
||||
# Device Type Revision: 1 (Matter 1.5+)
|
||||
# Class: Simple | Scope: Endpoint
|
||||
#
|
||||
# CLUSTERS (Server):
|
||||
# - 0x0430: Soil Measurement (M)
|
||||
# - 0x0003: Identify (M)
|
||||
# - 0x0402: Temperature Measurement (O) - not exposed by this plugin
|
||||
#
|
||||
# NOTES:
|
||||
# - Reads the `Moisture` value (percent) reported by Tasmota soil sensors,
|
||||
# e.g. Adafruit Seesaw capacitive soil sensor (xsns_81), or BLE plant sensors
|
||||
# - Soil temperature (optional on this device type) can be exposed with a
|
||||
# separate `temperature` endpoint using the same sensor filter prefix
|
||||
#################################################################################
|
||||
|
||||
#################################################################################
|
||||
# Matter 1.6.0 Soil Measurement Cluster (0x0430)
|
||||
#################################################################################
|
||||
# Cluster Revision: 1 (Matter 1.5+)
|
||||
# Role: Application | Scope: Endpoint | PICS: SOIL
|
||||
#
|
||||
# ATTRIBUTES:
|
||||
# ID | Name | Type | Quality | Conf
|
||||
# -------|--------------------------------|-------------------------|---------|-----
|
||||
# 0x0000 | SoilMoistureMeasurementLimits | MeasurementAccuracyStruct | F | M
|
||||
# 0x0001 | SoilMoistureMeasuredValue | percent (uint8) | X | M
|
||||
#
|
||||
# SoilMoistureMeasurementLimits constraints (spec 2.15.4.1):
|
||||
# - MeasurementType = SoilMoisture (17)
|
||||
# - MinMeasuredValue 0..99, MaxMeasuredValue (Min+1)..100
|
||||
# - a single AccuracyRanges entry covering [Min, Max], with only PercentMax
|
||||
# set; PercentMax (percent100ths) must be <= 10 (checked by TC_SOIL_2_1)
|
||||
#
|
||||
# SoilMoistureMeasuredValue: water content of the soil in percent,
|
||||
# null until the first reading.
|
||||
#################################################################################
|
||||
|
||||
import matter
|
||||
|
||||
# Matter plug-in for core behavior
|
||||
|
||||
#@ solidify:Matter_Plugin_Sensor_Soil,weak
|
||||
|
||||
class Matter_Plugin_Sensor_Soil : Matter_Plugin_Sensor
|
||||
static var TYPE = "soil" # name of the plug-in in json
|
||||
static var DISPLAY_NAME = "Soil Moisture" # display name of the plug-in
|
||||
static var JSON_NAME = "Moisture" # Name of the sensor attribute in JSON payloads
|
||||
static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Moisture")
|
||||
static var CLUSTERS = matter.consolidate_clusters(_class, {
|
||||
0x0430: [0,1], # Soil Measurement 2.15 - no writable
|
||||
})
|
||||
static var TYPES = { 0x0045: 1 } # Soil Sensor, rev 1
|
||||
|
||||
# static var MT_SOIL_MOISTURE = 17 # MeasurementTypeEnum SoilMoisture
|
||||
# static var PERCENT_MAX = 10 # percent100ths, upper bound checked by TC_SOIL_2_1 (and used by the CHIP reference server)
|
||||
|
||||
#############################################################
|
||||
# Pre-process value
|
||||
#
|
||||
# Tasmota reports moisture in percent, Matter uses a uint8 percent
|
||||
# Clamp in the float domain before converting, since `int()` of NaN
|
||||
# or out-of-range floats is undefined, then round to nearest
|
||||
def pre_value(val)
|
||||
if val == nil || val != val return nil end # nil or NaN
|
||||
if val < 0 val = 0 end
|
||||
if val > 100 val = 100 end
|
||||
return int(val + 0.5)
|
||||
end
|
||||
|
||||
#############################################################
|
||||
# Called when the value changed compared to shadow value
|
||||
def value_changed()
|
||||
self.attribute_updated(0x0430, 0x0001)
|
||||
end
|
||||
|
||||
#############################################################
|
||||
# update_virtual
|
||||
#
|
||||
# Clamp values received from `MtrUpdate {"Name":"...", "Moisture":42}`
|
||||
def update_virtual(payload)
|
||||
var val = payload.find(self.JSON_NAME)
|
||||
if val != nil
|
||||
payload[self.JSON_NAME] = self.pre_value(real(val))
|
||||
end
|
||||
super(self).update_virtual(payload)
|
||||
end
|
||||
|
||||
#############################################################
|
||||
# build SoilMoistureMeasurementLimits
|
||||
def _build_limits()
|
||||
var TLV = matter.TLV
|
||||
var lim = TLV.Matter_TLV_struct()
|
||||
lim.add_TLV(0, 0x06 #-TLV.U4-#, 17 #-MT_SOIL_MOISTURE-#) # MeasurementType
|
||||
lim.add_TLV(1, 0x08 #-TLV.BOOL-#, true) # Measured
|
||||
lim.add_TLV(2, 0x03 #-TLV.I8-#, 0) # MinMeasuredValue
|
||||
lim.add_TLV(3, 0x03 #-TLV.I8-#, 100) # MaxMeasuredValue
|
||||
var ranges = lim.add_array(4) # AccuracyRanges
|
||||
var r = ranges.add_struct()
|
||||
r.add_TLV(0, 0x03 #-TLV.I8-#, 0) # RangeMin
|
||||
r.add_TLV(1, 0x03 #-TLV.I8-#, 100) # RangeMax
|
||||
r.add_TLV(2, 0x06 #-TLV.U4-#, 10 #-PERCENT_MAX-#) # PercentMax
|
||||
return lim
|
||||
end
|
||||
|
||||
#############################################################
|
||||
# read an attribute
|
||||
#
|
||||
def read_attribute(session, ctx, tlv_solo)
|
||||
var cluster = ctx.cluster
|
||||
var attribute = ctx.attribute
|
||||
|
||||
# ====================================================================================================
|
||||
if cluster == 0x0430 # ========== Soil Measurement 2.15 ==========
|
||||
if attribute == 0x0000 # ---------- SoilMoistureMeasurementLimits / MeasurementAccuracyStruct ----------
|
||||
return self._build_limits()
|
||||
elif attribute == 0x0001 # ---------- SoilMoistureMeasuredValue / percent ----------
|
||||
return tlv_solo.set_or_nil(0x06 #-TLV.U4-#, self.shadow_value != nil ? int(self.shadow_value) : nil)
|
||||
end
|
||||
|
||||
end
|
||||
return super(self).read_attribute(session, ctx, tlv_solo)
|
||||
end
|
||||
|
||||
#############################################################
|
||||
# web_values
|
||||
#
|
||||
# Show values of the remote device as HTML
|
||||
def web_values()
|
||||
import webserver
|
||||
self.web_values_prefix() # display '| ' and name if present
|
||||
webserver.content_send(format("🌱 %i%%", self.shadow_value != nil ? int(self.shadow_value) : nil))
|
||||
end
|
||||
#############################################################
|
||||
#############################################################
|
||||
|
||||
end
|
||||
matter.Plugin_Sensor_Soil = Matter_Plugin_Sensor_Soil
|
||||
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# Matter_Plugin_Bridge_Sensor_Soil.be - implements base class for a Soil Sensor via HTTP to Tasmota
|
||||
#
|
||||
# Copyright (C) 2026 Ludovic BOUÉ
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#################################################################################
|
||||
# Matter 1.6.0 Bridge Variant - Soil Sensor via HTTP
|
||||
#################################################################################
|
||||
# INHERITS FROM: Matter_Plugin_Sensor_Soil (Matter_Plugin_3_Sensor_Soil.be)
|
||||
# VARIANT TYPE: Bridge (Remote HTTP Device)
|
||||
# DEVICE TYPE: Soil Sensor (0x0045) - See base class
|
||||
# CLUSTERS: Soil Measurement (0x0430) - See Matter_Plugin_3_Sensor_Soil.be
|
||||
# TYPE: "http_soil" | BRIDGE: true
|
||||
#################################################################################
|
||||
|
||||
import matter
|
||||
|
||||
# Matter plug-in for core behavior
|
||||
|
||||
#@ solidify:Matter_Plugin_Bridge_Sensor_Soil,weak
|
||||
|
||||
class Matter_Plugin_Bridge_Sensor_Soil : Matter_Plugin_Sensor_Soil
|
||||
static var BRIDGE = true # flag as bridged device
|
||||
static var TYPE = "http_soil" # name of the plug-in in json
|
||||
end
|
||||
matter.Plugin_Bridge_Sensor_Soil = Matter_Plugin_Bridge_Sensor_Soil
|
||||
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# Matter_Plugin_9_Virt_Sensor_Soil.be - implements Virtual Soil Sensor
|
||||
#
|
||||
# Copyright (C) 2026 Ludovic BOUÉ
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#################################################################################
|
||||
# Matter 1.6.0 Virtual Variant - Soil Sensor
|
||||
#################################################################################
|
||||
# INHERITS FROM: Matter_Plugin_Sensor_Soil (Matter_Plugin_3_Sensor_Soil.be)
|
||||
# VARIANT TYPE: Virtual
|
||||
# DEVICE TYPE: Soil Sensor (0x0045) - See base class for specification
|
||||
# CLUSTERS: Soil Measurement (0x0430) - See Matter_Plugin_3_Sensor_Soil.be
|
||||
# TYPE: "v_soil" | VIRTUAL: true
|
||||
#
|
||||
# TESTING:
|
||||
# MtrUpdate {"Name":"Garden", "Moisture":42}
|
||||
#################################################################################
|
||||
|
||||
import matter
|
||||
|
||||
# Matter plug-in for core behavior
|
||||
|
||||
#@ solidify:Matter_Plugin_Virt_Sensor_Soil,weak
|
||||
|
||||
class Matter_Plugin_Virt_Sensor_Soil : Matter_Plugin_Sensor_Soil
|
||||
static var TYPE = "v_soil" # name of the plug-in in json
|
||||
static var DISPLAY_NAME = "v.Soil Moisture" # display name of the plug-in
|
||||
|
||||
static var SCHEMA = nil # no parameter
|
||||
static var VIRTUAL = true # virtual device
|
||||
end
|
||||
matter.Plugin_Virt_Sensor_Soil = Matter_Plugin_Virt_Sensor_Soil
|
||||
@@ -190,20 +190,20 @@ class Matter_UI
|
||||
"|relay|relay_power|light0|light1|light2|light3|shutter|shutter+tilt"
|
||||
"|gensw_btn"
|
||||
"|temperature|pressure|illuminance|humidity|occupancy|onoff|contact|flow|rain|waterleak"
|
||||
"|airquality"
|
||||
"|airquality|soil"
|
||||
static var _CLASSES_TYPES_VIRTUAL =
|
||||
"-virtual|v_relay|v_relay_power|v_light0|v_light1|v_light2|v_light3"
|
||||
"|v_fan|v_hvac|v_hvac_option"
|
||||
"|v_temp|v_pressure|v_illuminance|v_humidity|v_occupancy|v_contact|v_flow|v_rain|v_waterleak"
|
||||
"|v_airquality"
|
||||
"|v_airquality|v_soil"
|
||||
static var _CLASSES_TYPES2= "|http_relay|http_relay_power|http_light0|http_light1|http_light2|http_light3"
|
||||
"|http_temperature|http_pressure|http_illuminance|http_humidity"
|
||||
"|http_occupancy|http_contact|http_flow|http_rain|http_waterleak"
|
||||
"|http_airquality"
|
||||
"|http_airquality|http_soil"
|
||||
static var _CLASSES_TYPES3= "|mqtt_relay|mqtt_light0|mqtt_light1|mqtt_light2|mqtt_light3"
|
||||
"|mqtt_temperature|mqtt_pressure|mqtt_illuminance|mqtt_humidity"
|
||||
"|mqtt_occupancy|mqtt_contact|mqtt_flow|mqtt_rain|mqtt_waterleak"
|
||||
"|mqtt_airquality"
|
||||
"|mqtt_airquality|mqtt_soil"
|
||||
var device
|
||||
var matter_enabled
|
||||
|
||||
|
||||
@@ -233,6 +233,17 @@ class Matter_Autoconf
|
||||
end
|
||||
end
|
||||
|
||||
# soil moisture sensors
|
||||
# Skip CHIRP sensors (xsns_48): their `Moisture` is raw capacitance, not percent
|
||||
import string
|
||||
for k1: k2l(sensors)
|
||||
var sensor_2 = sensors[k1]
|
||||
if isinstance(sensor_2, map) && sensor_2.contains("Moisture") && string.find(k1, "CHIRP") != 0
|
||||
var soil_rule = k1 + "#Moisture"
|
||||
ret.push({'type':'soil','filter':soil_rule})
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
Reference in new issue
Block a user