Skip to content

Commit 31a2447

Browse files
authored
Merge branch 'Koenkk:master' into futurehomeCharger
2 parents bc4d654 + 3a897e9 commit 31a2447

21 files changed

Lines changed: 1093 additions & 35 deletions

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "26.75.0"
2+
".": "26.77.0"
33
}

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
11
# Changelog
22

3+
## [26.77.0](https://github.com/Koenkk/zigbee-herdsman-converters/compare/v26.76.0...v26.77.0) (2026-07-02)
4+
5+
6+
### Features
7+
8+
* **add:** AY-204ZX ([#12517](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12517)) ([c4351ce](https://github.com/Koenkk/zigbee-herdsman-converters/commit/c4351ce5854affa320f1ca2d4481c8b321424ee0))
9+
* **add:** TOQCB2-80-2P ([#12602](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12602)) ([782eb74](https://github.com/Koenkk/zigbee-herdsman-converters/commit/782eb747150632a33365a5a82fd1cd804bdc0156))
10+
* **add:** ZSN-03P ([#12594](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12594)) ([ae45db6](https://github.com/Koenkk/zigbee-herdsman-converters/commit/ae45db6b9cba89f40a3c7c907113b4e64c4d8553))
11+
12+
13+
### Bug Fixes
14+
15+
* Soma SmartShades3: remove tilt control ([#12597](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12597)) ([4134983](https://github.com/Koenkk/zigbee-herdsman-converters/commit/413498303bda91e603f3017abed83bf0a55c4831))
16+
* SONOFF SWV: fix configure when optional attribute is unsupported ([#12600](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12600)) ([4146a1f](https://github.com/Koenkk/zigbee-herdsman-converters/commit/4146a1fcd4615872d8b34d7fc3155dc634190986))
17+
* Tuya TS011F_with_threshold: expose `child_lock` ([#12598](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12598)) ([0eddac3](https://github.com/Koenkk/zigbee-herdsman-converters/commit/0eddac344f4684ba896f9a62160ec0bcc3f5a67f))
18+
* Tuya: fix weather crash due to missing await ([#12595](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12595)) ([087766b](https://github.com/Koenkk/zigbee-herdsman-converters/commit/087766b0f3712773ef4191e993e79e2a681d68d5))
19+
20+
## [26.76.0](https://github.com/Koenkk/zigbee-herdsman-converters/compare/v26.75.0...v26.76.0) (2026-06-30)
21+
22+
23+
### Features
24+
25+
* **add:** 1800194 ([#12569](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12569)) ([14c3e81](https://github.com/Koenkk/zigbee-herdsman-converters/commit/14c3e8109da2b8b9400343891d765766524098d6))
26+
* **add:** 929004610601 https://github.com/Koenkk/zigbee2mqtt/issues/32440 ([92a75cb](https://github.com/Koenkk/zigbee-herdsman-converters/commit/92a75cbfd92dfbc8dc2364a4f60cbaf56e1e1124))
27+
* **add:** C200 ([#12591](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12591)) ([48f3c6d](https://github.com/Koenkk/zigbee-herdsman-converters/commit/48f3c6d20691c2f5e484d7a9a93ca1d938933b7e))
28+
* **add:** HM-5HA-E ([#12587](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12587)) ([701b983](https://github.com/Koenkk/zigbee-herdsman-converters/commit/701b983c16a794aee5d357c5c01213593fee1784))
29+
* **add:** MINI-ZB1GS ([#12590](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12590)) ([3fccb19](https://github.com/Koenkk/zigbee-herdsman-converters/commit/3fccb197757751b3cf4e895e9ee477d4cd8a0522))
30+
* **add:** SISWD11-ZB ([#12588](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12588)) ([28c99e6](https://github.com/Koenkk/zigbee-herdsman-converters/commit/28c99e635840f66f6fdfaa9dfb9903ba936fb4a8))
31+
* **add:** SNZB-02UL ([#12589](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12589)) ([c62ee3d](https://github.com/Koenkk/zigbee-herdsman-converters/commit/c62ee3d2a55f99b8b0d2b1d9f87d1bd820ea5976))
32+
* **add:** WB-MSW-ZIGBEE_v.4_official ([#12582](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12582)) ([d056c5c](https://github.com/Koenkk/zigbee-herdsman-converters/commit/d056c5c3563789db642a7f24c39ef4de0cfbc4dd))
33+
* IKEA E2134: support on duration, trigger condition ([#12566](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12566)) ([dcb6b9b](https://github.com/Koenkk/zigbee-herdsman-converters/commit/dcb6b9b886573f68cab3bed4a8d8040d66f6b1bf))
34+
* OWON PIR313-E: expose battery percentage and configure reporting ([#12583](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12583)) ([0cd2f9c](https://github.com/Koenkk/zigbee-herdsman-converters/commit/0cd2f9c85d45aecc5490bbf5486d9a2be4e55f57))
35+
36+
37+
### Bug Fixes
38+
39+
* Tuya TS011F_plug_1 `_TZ3008_reatplte`: report correct voltage/power ([#12545](https://github.com/Koenkk/zigbee-herdsman-converters/issues/12545)) ([5589f90](https://github.com/Koenkk/zigbee-herdsman-converters/commit/5589f90e128faac0929a4821025511c51fc59730))
40+
341
## [26.75.0](https://github.com/Koenkk/zigbee-herdsman-converters/compare/v26.74.0...v26.75.0) (2026-06-29)
442

543

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zigbee-herdsman-converters",
3-
"version": "26.75.0",
3+
"version": "26.77.0",
44
"description": "Collection of device converters to be used with zigbee-herdsman",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/devices/develco.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,23 @@ const zhemi101GetMeterConfig = (
212212
};
213213
};
214214

215+
const zhemi101PublishMissingMeterConfig = (payload: KeyValueAny, meta: Fz.Meta, config: KeyValueAny) => {
216+
const fields = {
217+
unit_of_measure: config.unitOfMeasure,
218+
metering_device_type: config.meteringDeviceType,
219+
multiplier: config.multiplier,
220+
divisor: config.divisor,
221+
summation_formatting: config.summationFormatting,
222+
demand_formatting: config.demandFormatting,
223+
};
224+
225+
for (const [property, value] of Object.entries(fields)) {
226+
if (value !== undefined && meta.state?.[property] == null) {
227+
payload[property] = value;
228+
}
229+
}
230+
};
231+
215232
const zhemi101GetMeterConfigFromEntity = (entity: KeyValueAny, meta: Tz.Meta): KeyValueAny => {
216233
const cached = zhemi101MeterConfigCache.get(zhemi101MeterConfigKey(entity)) ?? {};
217234
const interfaceMode = zhemi101FirstDefined(cached.interfaceMode, meta.state?.interface_mode);
@@ -264,12 +281,14 @@ const zhemi101NormalizeMeterValue = (rawValue: unknown, config: KeyValueAny, isD
264281
const unitInfo = zhemi101UnitInfo[zhemi101ToNumber(config.unitOfMeasure) ?? -1];
265282
if (unitInfo === undefined) return undefined;
266283

267-
const normalized = raw * zhemi101Scale(config) * unitInfo.factorToTarget;
284+
// The spec scales electric demand to kW; Z2M's power property is W.
285+
const factorToTarget = isDemand && unitInfo.kind === "energy" ? unitInfo.factorToTarget * 1000 : unitInfo.factorToTarget;
286+
const normalized = raw * zhemi101Scale(config) * factorToTarget;
268287
const sourceDecimals = zhemi101DecimalsFromFormatting(
269288
isDemand ? config.demandFormatting : config.summationFormatting,
270289
zhemi101DecimalsFromDivisor(config.divisor),
271290
);
272-
const extraDecimals = unitInfo.factorToTarget === 1 ? 0 : unitInfo.factorToTarget < 1 ? Math.ceil(-Math.log10(unitInfo.factorToTarget)) + 2 : 2;
291+
const extraDecimals = factorToTarget === 1 ? 0 : factorToTarget < 1 ? Math.ceil(-Math.log10(factorToTarget)) + 2 : 2;
273292
return utils.precisionRound(normalized, Math.min(9, sourceDecimals + extraDecimals));
274293
};
275294

@@ -407,6 +426,7 @@ const develco = {
407426
const data = msg.data as KeyValueAny;
408427
const payload: KeyValueAny = {};
409428
const summationFormatting = zhemi101FirstDefined(data.summaFormatting, data.summationFormatting);
429+
zhemi101PublishMissingMeterConfig(payload, meta, config);
410430

411431
if (data.unitOfMeasure !== undefined) payload.unit_of_measure = data.unitOfMeasure;
412432
if (data.meteringDeviceType !== undefined) payload.metering_device_type = data.meteringDeviceType;
@@ -1206,6 +1226,7 @@ export const definitions: DefinitionWithExtend[] = [
12061226
model: "ZHEMI101",
12071227
vendor: "Develco",
12081228
description: "Energy/gas/water meter interface",
1229+
version: "0.0.1",
12091230
fromZigbee: [develco.fz.metering_zhemi101, develco.fz.pulse_configuration, develco.fz.interface_mode],
12101231
toZigbee: [develco.tz.pulse_configuration, develco.tz.interface_mode_zhemi101, develco.tz.unit_summation_zhemi101],
12111232
endpoint: (device) => {
@@ -1226,7 +1247,7 @@ export const definitions: DefinitionWithExtend[] = [
12261247
exposes: [
12271248
e.energy().withDescription("Normalized cumulative energy. Source units such as kWh or BTU are converted to kWh."),
12281249
e.produced_energy().withDescription("Normalized produced energy, when reported by the meter."),
1229-
e.power().withUnit("kW").withDescription("Normalized instantaneous demand. Source units such as kW or BTU/h are converted to kW."),
1250+
e.power().withDescription("Normalized instantaneous demand. Source units such as kW or BTU/h are converted to W."),
12301251
e
12311252
.numeric("gas", ea.STATE)
12321253
.withUnit("m³")

src/devices/heiman.ts

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,8 +2587,16 @@ export const definitions: DefinitionWithExtend[] = [
25872587
heimanExtend.heimanClusterSpecial(),
25882588
m.deviceEndpoints({endpoints: {l1: 1, l2: 2}}),
25892589
m.onOff({endpointNames: ["l1", "l2"]}),
2590-
m.deviceTemperature(),
25912590
m.identify(),
2591+
m.numeric({
2592+
name: "device_intenal_temperature",
2593+
cluster: "genDeviceTempCfg",
2594+
attribute: "currentTemperature",
2595+
description: "Temperature of the device",
2596+
unit: "°C",
2597+
access: "STATE_GET",
2598+
entityCategory: "diagnostic",
2599+
}),
25922600
m.enumLookup<"heimanClusterSpecial", HeimanPrivateCluster>({
25932601
name: "switch_type_l1",
25942602
endpointName: "l1",
@@ -3643,16 +3651,6 @@ export const definitions: DefinitionWithExtend[] = [
36433651
access: "ALL",
36443652
}),
36453653
heimanExtend.heimanClusterRadarDetectionRange(),
3646-
m.numeric<"heimanClusterSpecial", HeimanPrivateCluster>({
3647-
name: "repeated_reporting_duration",
3648-
unit: "minute(s)",
3649-
valueMin: 0,
3650-
valueMax: 65535,
3651-
cluster: "heimanClusterSpecial",
3652-
attribute: "occupiedToOccupiedDuration",
3653-
description: "occupied repeated reporting duartion, 65535 indicates forever",
3654-
access: "ALL",
3655-
}),
36563654
m.numeric<"heimanClusterSpecial", HeimanPrivateCluster>({
36573655
name: "illuminance_threshold",
36583656
unit: "lx",
@@ -3682,17 +3680,18 @@ export const definitions: DefinitionWithExtend[] = [
36823680
}),
36833681
heimanExtend.temperatureOffset(),
36843682
heimanExtend.humidityOffset(),
3685-
m.enumLookup<"heimanClusterSpecial", HeimanPrivateCluster>({
3683+
m.binary<"heimanClusterSpecial", HeimanPrivateCluster>({
36863684
name: "learning_control",
3687-
lookup: {start: 65534, reset: 65535},
3685+
valueOn: ["start", 65534],
3686+
valueOff: ["reset", 65535],
36883687
cluster: "heimanClusterSpecial",
36893688
attribute: "radarLearningControl",
36903689
description: "Radar learning mode, please wake up the device first.",
36913690
access: "STATE_SET",
36923691
}),
36933692
m.enumLookup<"heimanClusterSpecial", HeimanPrivateCluster>({
36943693
name: "learning_state",
3695-
lookup: {not: 0, learning: 1, completed: 2, failed: 3},
3694+
lookup: {normal: 0, learning: 1, completed: 2, failed: 3},
36963695
cluster: "heimanClusterSpecial",
36973696
attribute: "radarLearningState",
36983697
description: "radar learning state",
@@ -3713,4 +3712,57 @@ export const definitions: DefinitionWithExtend[] = [
37133712
],
37143713
ota: true,
37153714
},
3715+
{
3716+
zigbeeModel: ["HM-5HA-E", "HM-5HA-EF-3.0"],
3717+
model: "HM-5HA-E",
3718+
vendor: "Heiman",
3719+
description: "Heat detector",
3720+
fromZigbee: [fzLocal.heimanClusterSpecialfz],
3721+
toZigbee: [tz.warning],
3722+
configure: async (device, coordinatorEndpoint) => {
3723+
const endpoint = device.getEndpoint(1);
3724+
await reporting.bind(endpoint, coordinatorEndpoint, ["genPowerCfg", "heimanClusterSpecial"]);
3725+
await reporting.batteryPercentageRemaining(endpoint);
3726+
await endpoint.read("ssIasZone", ["zoneStatus", "zoneState", "iasCieAddr", "zoneId"]);
3727+
await endpoint.read("msTemperatureMeasurement", ["measuredValue"]);
3728+
await endpoint.read<"heimanClusterSpecial", HeimanPrivateCluster>(
3729+
"heimanClusterSpecial",
3730+
[
3731+
"sensorFaultState",
3732+
"deviceMuteControl",
3733+
"deviceMuteState",
3734+
"indicatorLightLevelControlOf1",
3735+
"interconnectable",
3736+
"temperatureOffset",
3737+
"rebootedCount",
3738+
"rejoinedCount",
3739+
"reportedPackages",
3740+
],
3741+
{
3742+
manufacturerCode: Zcl.ManufacturerCode.HEIMAN_TECHNOLOGY_CO_LTD,
3743+
},
3744+
);
3745+
},
3746+
exposes: [],
3747+
extend: [
3748+
m.battery(),
3749+
m.identify(),
3750+
m.temperature(),
3751+
m.iasZoneAlarm({zoneType: "alarm", zoneAttributes: ["alarm_1", "battery_low", "test", "tamper"]}),
3752+
heimanExtend.heimanClusterSpecial(),
3753+
heimanExtend.heimanClusterSensorFaultState(),
3754+
heimanExtend.heimanClusterDeviceMuteState(),
3755+
heimanExtend.iasZoneInitiateTestMode(),
3756+
heimanExtend.heimanClusterSensorMutable(),
3757+
heimanExtend.heimanClusterIndicatorLight(),
3758+
heimanExtend.heimanClusterSensorInterconnectable(),
3759+
heimanExtend.sirenForAutomationOnly(),
3760+
heimanExtend.temperatureOffset(),
3761+
heimanExtend.linkAvailable(),
3762+
heimanExtend.reportedPackages(),
3763+
heimanExtend.rejoinedCount(),
3764+
heimanExtend.rebootedCount(),
3765+
],
3766+
ota: true,
3767+
},
37163768
];

src/devices/ikea.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {Zcl} from "zigbee-herdsman";
33
import {repInterval} from "../lib/constants";
44
import {
55
addCustomClusterManuSpecificIkeaAirPurifier,
6+
addCustomClusterManuSpecificIkeaMotionSensor,
67
addCustomClusterManuSpecificIkeaSmartPlug,
78
addCustomClusterManuSpecificIkeaUnknown,
89
addCustomClusterManuSpecificIkeaVocIndexMeasurement,
@@ -19,6 +20,8 @@ import {
1920
ikeaLight,
2021
ikeaMediaCommands,
2122
ikeaModernExtend,
23+
ikeaMotionSensorOnDuration,
24+
ikeaMotionSensorTriggerMode,
2225
ikeaVoc,
2326
styrbarCommandOn,
2427
tradfriCommandsLevelCtrl,
@@ -1231,10 +1234,13 @@ export const definitions: DefinitionWithExtend[] = [
12311234
description: "VALLHORN wireless motion sensor",
12321235
extend: [
12331236
addCustomClusterManuSpecificIkeaUnknown(),
1237+
addCustomClusterManuSpecificIkeaMotionSensor(),
12341238
m.occupancy(),
12351239
m.illuminance(),
12361240
m.identify({isSleepy: true}),
12371241
m.battery({voltage: true, voltageReporting: true}),
1242+
ikeaMotionSensorTriggerMode(),
1243+
ikeaMotionSensorOnDuration(),
12381244
],
12391245
ota: true,
12401246
},

src/devices/lumi.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,6 +2812,37 @@ export const definitions: DefinitionWithExtend[] = [
28122812
lumiZigbeeOTA(),
28132813
],
28142814
},
2815+
{
2816+
zigbeeModel: ["lumi.curtain.acn018"],
2817+
model: "C200",
2818+
vendor: "Aqara",
2819+
description: "Curtain motor",
2820+
toZigbee: [lumi.toZigbee.lumi_curtain_limits_calibration, lumi.toZigbee.lumi_curtain_automatic_calibration_ZNCLDJ01LM],
2821+
exposes: [
2822+
e.enum("limits_calibration", ea.SET, ["start", "end", "reset"]).withDescription("Calibrate the position limits"),
2823+
e
2824+
.enum("automatic_calibration", ea.SET, ["calibrate"])
2825+
.withDescription("Performs an automatic calibration process similar to Aqara’s method to set curtain limits."),
2826+
],
2827+
extend: [
2828+
lumi.modernExtend.addManuSpecificLumiCluster(),
2829+
m.windowCovering({controls: ["lift"], coverInverted: true, configureReporting: true}),
2830+
lumiCurtainSpeed(),
2831+
lumiCurtainManualOpenClose(),
2832+
lumiCurtainAdaptivePullingSpeed(),
2833+
lumiCurtainManualStop(),
2834+
lumiCurtainReverse(),
2835+
lumiCurtainStatus(),
2836+
lumiCurtainLastManualOperation(),
2837+
lumiCurtainPosition(),
2838+
lumiCurtainTraverseTime(),
2839+
lumiCurtainCalibrationStatus(),
2840+
lumiCurtainCalibrated(),
2841+
lumiCurtainIdentifyBeep(),
2842+
m.identify(),
2843+
lumiZigbeeOTA(),
2844+
],
2845+
},
28152846
{
28162847
zigbeeModel: ["lumi.curtain.acn002"],
28172848
model: "ZNJLBL01LM",

src/devices/mercator.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,20 @@ export const definitions: DefinitionWithExtend[] = [
188188
await endpoint.write("hvacFanCtrl", {fanModeSequence: 0});
189189
},
190190
},
191+
{
192+
fingerprint: tuya.fingerprint("TS0601", ["_TZE200_jowqowye"]),
193+
model: "SISWD11-ZB",
194+
vendor: "Mercator Ikuü",
195+
description: "Inline module dimmer switch",
196+
extend: [tuya.modernExtend.tuyaBase({dp: true})],
197+
exposes: [tuya.exposes.lightBrightness()],
198+
meta: {
199+
tuyaDatapoints: [
200+
[1, "state", tuya.valueConverter.onOff],
201+
[2, "brightness", tuya.valueConverter.scale0_254to0_1000],
202+
],
203+
},
204+
},
191205
{
192206
fingerprint: tuya.fingerprint("TS011F", ["_TZ3210_pfbzs1an"]),
193207
model: "SPPUSB02",

src/devices/owon.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -909,19 +909,21 @@ export const definitions: DefinitionWithExtend[] = [
909909
description: "Motion sensor",
910910
fromZigbee: [fz.battery, fz.ias_occupancy_alarm_1, fz.temperature, fz.humidity, fz.occupancy_timeout],
911911
toZigbee: [],
912-
exposes: [e.occupancy(), e.tamper(), e.battery_low(), e.temperature(), e.humidity()],
912+
exposes: [e.occupancy(), e.tamper(), e.battery_low(), e.battery(), e.temperature(), e.humidity()],
913913
configure: async (device, coordinatorEndpoint) => {
914+
const endpoint1 = device.getEndpoint(1);
914915
const endpoint2 = device.getEndpoint(2);
915916
const endpoint3 = device.getEndpoint(3);
916-
if (device.modelID === "PIR313") {
917-
await reporting.bind(endpoint3, coordinatorEndpoint, ["msTemperatureMeasurement", "msRelativeHumidity"]);
918-
} else {
919-
await reporting.bind(endpoint2, coordinatorEndpoint, ["msTemperatureMeasurement", "msRelativeHumidity"]);
920-
}
917+
await reporting.bind(endpoint1, coordinatorEndpoint, ["genPowerCfg"]);
918+
await reporting.batteryPercentageRemaining(endpoint1, {min: 3600, max: 65000, change: 10});
919+
const measurementEndpoint = device.modelID === "PIR313" ? endpoint3 : endpoint2;
920+
await reporting.bind(measurementEndpoint, coordinatorEndpoint, ["msTemperatureMeasurement", "msRelativeHumidity"]);
921+
await reporting.temperature(measurementEndpoint, {min: 60, max: 3600, change: 50});
922+
await reporting.humidity(measurementEndpoint, {min: 60, max: 3600, change: 100});
921923
device.powerSource = "Battery";
922924
device.save();
923925
},
924-
extend: [m.illuminance()],
926+
extend: [m.illuminance({reporting: {min: 300, max: 3600, change: 100}})],
925927
},
926928
{
927929
zigbeeModel: ["AC201", "AC201P_019E"],

0 commit comments

Comments
 (0)