diff --git a/fhem/FHEM/lib/AttrTemplate/mqtt2.template b/fhem/FHEM/lib/AttrTemplate/mqtt2.template
index 2184f78bc..8216e8338 100644
--- a/fhem/FHEM/lib/AttrTemplate/mqtt2.template
+++ b/fhem/FHEM/lib/AttrTemplate/mqtt2.template
@@ -1172,14 +1172,48 @@ attr DEVICE setList \
attr DEVICE periodicCmd temperature:55
attr DEVICE devStateIcon LOCKED:secur_lock:btnLock+UNLOCK UNLOCKED:secur_open:btnLock+LOCK
attr DEVICE webCmd desired-temp
-attr DEVICE jsonMap current_heating_setpoint:desired-temp local_temperature:temperature Battery:batteryPercent system_mode:mode voltage:batterymV
+attr DEVICE jsonMap current_heating_setpoint:desired-temp local_temperature:temperature Battery:batteryPercent system_mode:mode voltage:batterymV child_lock:btnLock
attr DEVICE stateFormat btnLock\
Measured: temperature Battery: batteryPercent %
attr DEVICE userReadings batteryState:battery_low.* {ReadingsVal($name,'battery_low','false') eq 'false'?'ok':'low'}, batteryVoltage:batterymV.* {ReadingsNum($name,'batterymV',0)/1000}
attr DEVICE model zigbee2mqtt_thermostat_without_weekrofile
set DEVICE attrTemplate speechcontrol_type_thermostat
deletereading -q DEVICE (?!associatedWith|IODev).*
-setreading DEVICE attrTemplateVersion 20240108
+setreading DEVICE attrTemplateVersion 20240402
+
+
+#contributed by clumsy via pm
+name:zigbee2mqtt_thermostat_with_weekrofile_5_1_1
+desc: Developed for Models Moes BHT-002/BHT-006 via zigbee2mqtt
+filter:TYPE=MQTT2_DEVICE:FILTER=CID~zigbee.*
+order:L_17b1
+par:BASE_TOPIC;base topic set in configuration.yaml of the zigbee2mqtt bridge;{ AttrVal("DEVICE","devicetopic",AttrVal("DEVICE","readingList","")) =~ m,[\b]?([^/:]+)[/].+, ? $1 : undef }
+par:DEV_ID;name of the device in the zigbee2mqtt bridge;{ AttrVal("DEVICE","devicetopic",AttrVal("DEVICE","readingList","")) =~ m,[^/]+[/]([^/:]+).*, ? $1 : undef }
+par:ICON;ICON as set, defaults to temp_control;{ AttrVal("DEVICE","icon","temp_control") }
+attr DEVICE icon ICON
+attr DEVICE devicetopic BASE_TOPIC/DEV_ID
+attr DEVICE readingList $\DEVICETOPIC:.* { json2nameValue($EVENT,'',$JSONMAP) }
+attr DEVICE setList \
+ desired-temp:slider,5.0,0.5,30.0,1 $\DEVICETOPIC/set {"current_heating_setpoint": $EVTPART1}\
+ btnLock:LOCK,UNLOCK $\DEVICETOPIC/set {"child_lock": "$EVTPART1"}\
+ mode:heat,off $\DEVICETOPIC/set {"system_mode": "$EVTPART1"}\
+ preset:hold,program $\DEVICETOPIC/set {"preset": "$EVTPART1"}\
+ saturday $\DEVICETOPIC/set/schedule { "saturday":[$EVTPART1] }\
+ sunday $\DEVICETOPIC/set/schedule { "sunday":[$EVTPART1] }\
+ weekdays $\DEVICETOPIC/set/schedule { "weekdays":[$EVTPART1] }\
+ weekprofile { no strict 'vars';; FHEM::attrT_z2m_thermostat_Utils::z2t_send_BHT($NAME, $EVTPART1, $EVTPART2) }\
+ x_send_set_payload:textField { my $payload = $EVENT;;$payload =~ s/$EVTPART0 //;; qq($\DEVICETOPIC/set $payload)}
+attr DEVICE devStateIcon LOCKED:secur_lock:btnLock+UNLOCK UNLOCKED:secur_open:btnLock+LOCK
+attr DEVICE webCmd desired-temp
+attr DEVICE jsonMap current_heating_setpoint:desired-temp local_temperature:temperature Battery:batteryPercent system_mode:mode voltage:batterymV child_lock:btnLock
+attr DEVICE stateFormat btnLock\
+Measured: temperature Battery: batteryPercent %
+attr DEVICE userReadings batteryState:battery_low.* {ReadingsVal($name,'battery_low','false') eq 'false'?'ok':'low'}, batteryVoltage:batterymV.* {ReadingsNum($name,'batterymV',0)/1000}
+attr DEVICE model zigbee2mqtt_thermostat_with_weekrofile_5_1_1
+set DEVICE attrTemplate speechcontrol_type_thermostat
+deletereading -q DEVICE (?!associatedWith|IODev).*
+setreading DEVICE attrTemplateVersion 20240402
+
###########################################
# TASMOTA
diff --git a/fhem/contrib/AttrTemplate/99_attrT_z2m_thermostat_Utils.pm b/fhem/contrib/AttrTemplate/99_attrT_z2m_thermostat_Utils.pm
index b485279be..1a648df65 100644
--- a/fhem/contrib/AttrTemplate/99_attrT_z2m_thermostat_Utils.pm
+++ b/fhem/contrib/AttrTemplate/99_attrT_z2m_thermostat_Utils.pm
@@ -56,7 +56,7 @@ my %jsonmap = (
sub z2t_send_weekprofile {
my $name = shift // carp q[No device name provided!] && return;
my $wp_name = shift // carp q[No weekprofile device name provided!] && return;
- my $wp_profile = shift // carp q[No weekprofile profile name provided!] && return;
+ my $wp_profile = shift // AttrVal($name, 'weekprofile', undef) // carp q[No weekprofile profile name provided!] && return;
my $model = shift // ReadingsVal($name,'week','5+2');
my $topic = shift // AttrVal($name,'devicetopic','') . '/set';
@@ -111,7 +111,7 @@ sub z2t_send_weekprofile {
sub z2t_send_Beca_weekprofile {
my $name = shift // carp q[No device name provided!] && return;
my $wp_name = shift // carp q[No weekprofile device name provided!] && return;
- my $wp_profile = shift // carp q[No weekprofile profile name provided!] && return;
+ my $wp_profile = shift // AttrVal($name, 'weekprofile', undef) // carp q[No weekprofile profile name provided!] && return;
my $topic = shift // carp q[No topic to send to provided!] && return;
my $hash = $defs{$name};
@@ -151,6 +151,59 @@ sub z2t_send_Beca_weekprofile {
return qq{$topic $payload};
}
+
+sub z2t_send_BHT {
+ my $name = shift // carp q[No device name provided!] && return;
+ my $wp_name = shift // carp q[No weekprofile device name provided!] && return;
+ my $wp_profile = shift // AttrVal($name, 'weekprofile', undef) // carp q[No weekprofile profile name provided!] && return;
+ my $topic = shift // AttrVal($name,'devicetopic','') . '/set';
+
+ my $hash = $defs{$name};
+
+ my $wp_profile_data = CommandGet(undef,"$wp_name profile_data $wp_profile 0");
+ if ($wp_profile_data =~ m{(profile.*not.found|usage..profile_data..name)}xms ) {
+ Log3( $hash, 3, "[$name] weekprofile $wp_name: no profile named \"$wp_profile\" available" );
+ return;
+ }
+
+ my @D = qw(Sun Mon Tue Wed Thu Fri Sat); # eqals to my @D = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
+ my $today = (localtime(time))[6];
+ # if ( !($today ~~ [1..5]) ) {$today = 1};
+ if ( !(0 < $today < 6) ) {$today = 1};
+ Log3($hash, 3, "Fetching weekprofile for ${name} day ${today} / $D[${today}] from ${wp_name}/${wp_profile}");
+ my @days = ($today,6,0);
+ my $payload;
+ my $decoded;
+ if ( !eval { $decoded = decode_json($wp_profile_data) ; 1 } ) {
+ Log3($name, 1, "JSON decoding error in $wp_profile provided by $wp_name: $@");
+ return;
+ }
+
+ for my $i (@days) {
+ my $sd = $i == 0 ? 'sunday' : $i == 6 ? 'saturday' : 'weekdays';
+
+ for my $j (0..3) {
+ my $time = $decoded->{$D[$i]}{'time'}[$j];
+ last if !defined $time;
+ my ($hour,$minute) = split m{:}xms, $time;
+ $hour += 0;
+ $minute += 0;
+ my $tmp = $decoded->{$D[$i]}{'temp'}[$j]+0;
+ my $k = $j+1;
+ next if !looks_like_number($tmp);
+ $payload .= defined $payload ? ',' : '{';
+ $payload .= qq("${sd}_p${k}_hour":$hour,"${sd}_p${k}_minute":$minute,"${sd}_p${k}_temperature":$tmp);
+ }
+ }
+ return if !defined $payload;
+ $payload = '{"program":'.$payload;
+ $payload .='}}';
+ #Log3($hash,3,"Setting $name to new weekprofile: $payload");
+ readingsSingleUpdate( $hash, 'weekprofile', "$wp_name $wp_profile",1);
+ return qq{$topic $payload};
+}
+
+
1;
__END__