MClimate: fix driver defects, add missing encoders, add PIR Mini - #285
Open
MClimate wants to merge 1 commit into
Open
MClimate: fix driver defects, add missing encoders, add PIR Mini#285MClimate wants to merge 1 commit into
MClimate wants to merge 1 commit into
Conversation
Aligns vendors/mclimate with MClimate's own source of truth (the
mclimate-payload-helper package that drives our backend, public client
scripts and documentation). The entries were originally imported from our
docs by Actility and had drifted.
Correctness (12 drivers):
- ht-sensor: temperature low byte was not zero-padded, so readings whose
raw low byte was < 0x10 decoded wildly wrong (-36 C instead of +12 C);
battery used a legacy formula instead of (raw*8+1600)/1000; external
thermistor bytes were ignored.
- fan-coil: setFrostProtection transmitted 0x4F (the GET id) so enabling
frost protection only read it back; getFrostProtection sent 0x4D (get
ECM relay); two GETs were unreachable behind duplicate case labels;
setWatchDogParams threw; four response scalings were wrong (0x6d was
100x off).
- wireless-thermostat: setTargetTemperature always emitted 0x2E + 2 bytes;
the device expects 0x2E + 1 byte for integers and 0x50 + 2 bytes for
decimals. The shipped example asserted the wrong frame.
- 16a-switch-power-meter: internal temperature ignored the sign bit
(+133 C instead of -5 C); two thresholds were encoded a byte short.
- co2-display, co2-display-lite, ht-pir-lite: wrong keepalive strip
lengths leaked payload bytes into command parsing.
- vicki: decodeDownlink was never exported (the one failing example in the
catalog today), plus six decode fixes and four encoder fixes.
- flood-sensor: fraud events decoded without a reason; command answers
were misread as keepalives.
- open-close-sensor: command 0x1f was mislabelled sendEventLater.
Completeness:
- Every device now has a working encodeDownlink and decodeDownlink; ten
had none or an error stub. Commands are derived from the package command
classes (t-valve 29, co2-display 46, co2-notifier 25, button 18, ...).
- Full command-answer coverage; decoders return {errors:[...]} per TS013
instead of throwing or emitting NaN.
- PIR-lite drivers offered PIR commands their firmware does not implement;
replaced with the documented set.
- Removed dead DataCake/Milesight/ChirpStack wrapper functions.
- Examples grew from 44 to 213 across 18 drivers; all pass.
New device:
- PIR Mini (mclimate:pir-mini:1), verified against our published API docs.
Regional availability:
- Six models had no EU868 profile at all; the two 16A relays were
EU868-only. Every actively sold model now covers eu868, us915/au915 and
as923 with the class its hardware uses.
Housekeeping:
- AQI Sensor & Notifier is discontinued: model flagged deprecated and its
profile marked (deprecated). The driver is kept so units already in the
field still decode.
- Removed dangling os1-mcli protocolIds from seven models.
- All device images normalised to 256x256; three empty sensor lists
filled from the Actility ontology.
- vendor.yaml: corrected the display name to MClimate, added a full
description, website, products page and contact.
Some decoded field names changed to match the package and our published
codecs (details in the pull request description).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Brings the whole
vendors/mclimatefolder in line with MClimate's own source of truth(the
mclimate-payload-helperpackage, which drives our backend, our public clientscripts and our docs). The entries were originally imported from our documentation by
Actility, and had drifted.
encodeDownlink+decodeDownlink(10 had none or an error stub) and full command-answer coverage.
All 18 drivers pass the catalog harness (
DRIVER_PATH=<driver> npx jest driver-examples.spec.js): 213 examples, 0 failures, ESLint clean.Please review these deliberate output-schema changes
These rename decoded fields, so they are visible to existing ThingPark users. In every
case the new name matches the
mclimate-payload-helperpackage and the decoder wepublish to customers, so the catalog was the outlier.
temperature,humiditysensorTemperature,relativeHumidity(+thermistorProperlyConnected,extThermistorTemperature)co2,temperature,humidity,batteryCO2,sensorTemperature,relativeHumidity,batteryVoltageco2-notifier, which already used these namesppmCO2co2-display-liteand the packagerelayState: "ON"/"OFF"relayState: true/falseenergy_kWh,power_W,acVoltage_V,acCurrent_mAenergy,power,acVoltage,acCurrentsensors:ontology, not in field namessendEventLater(for cmd0x1f)notificationBlindTime0x1fis notification blind time on this device;sendEventLateris the Button's semanticproportionalAlgoParams,algoType,piMaxIntegratedError,effectiveMotorRange,internalAlgoTempState, andopenWindowParamsfor cmd0x46proportionalAlgorithmParameters,temperatureControlAlgorithm(mapped string),maxAllowedIntegralValue,valveOpennessRangeInPercentage,internalAlgoTemporaryState(boolean),openWindowPrecisely0x46previously collided with the realopenWindowParamsfrom0x13and silently overwrote itHappy to keep any legacy name for backward compatibility if you prefer — say which.
Highest-impact bugs fixed (all were reachable with real payloads)
string, so any reading whose raw low byte was
< 0x10decoded wildly wrong(e.g. −36 °C reported instead of +12 °C). Battery also used a legacy
2 + nibble*0.1formula instead of(raw*8+1600)/1000.setFrostProtectiontransmitted0x4F— the GET id — so asking thedevice to enable frost protection merely read the setting back.
getFrostProtectionsent
0x4D(get ECM relay). Two more GETs were unreachable behind duplicatecaselabels, and
setWatchDogParamsthrew a TypeError.setTargetTemperaturealways emitted0x2E+ 2 bytes; thedevice expects
0x2E+ 1 byte for integers and0x50+ 2 bytes for decimals. Theshipped example asserted the wrong frame, so tests passed.
−5 °C) and encoded
setOvervoltageThresholds/setOverpowerThresholdone byteshort (3680 W was emitted as a non-byte value).
co2-displaystripped 8 bytes instead of 11,co2-display-lite8 instead of 10,ht-pir-lite7 instead of 6. Leaked bytes werere-parsed as commands, fabricating fields (
keepAliveTime: null) or truncating thelast argument of every command answer.
decodeDownlinkwas defined but never exported — the one red test in thecatalog today. Plus
reasonreported81instead of129on the0x81keepalive,two status bits were missing,
tempHysteresislacked/10, and the open-windowdelta nibble decoded as
NaNfor values ≥ 10.0x80) decoded with noreasonat all — and treated any payload > 3 bytes as a long keepalive, so commandanswers became garbage.
(
0x3c,0x48,0x4a,0x4c) while missing the real ones. Their shipped downlinkexample demonstrated a command the device would reject.
New device
PIR Mini (
mclimate:pir-mini:1) — occupancy sensor with temperature, humidity andlight. Decoding verified field-for-field against our published API documentation, and
covers all three light-sensor states (reading / disabled / sensor error) plus the
0x3a/0x3b/0x40occupancy and trigger events. 27 encodable commands.Image supplied by MClimate and converted to the required 256×256 PNG.
Regional availability (EU868 fix)
Customer feedback said many MClimate devices could not be selected on EU868. Auditing
every model's
deviceProfileIdsagainst the ISM bands its profiles declare showed sixClass A models with no EU868 profile at all — only
us915,au915(RFGroup2) andas923(RFGroup4):wireless-thermostat
All six now also list
mclimate_RFGroup1_1.0.3a_classA(eu868, plus cn779/in865/eu433/kr920/ru864). All 18 models now cover EU868, and no model mixes LoRaWAN classes.
The 16A Dry Switch, 16A Switch & Power Meter and Fan Coil Thermostat are Class C devices
and already carried the EU868 Class C profile, so they needed no change.
The two 16A relays were also EU868-only; they now carry
mclimate_RFGroup2_1.0.3a_classC(us915, au915) andmclimate_RFGroup4_1.0.3a_classC(as923). Every actively sold model now covers eu868 + us915/au915 + as923, each with
the LoRaWAN class its hardware actually uses (Class C for the two relays and the Fan Coil
Thermostat, Class A for everything else).
Discontinued product: AQI Sensor & Notifier
MClimate has stopped selling and supporting the Air Quality Sensor & Notifier (AQI).
models/aqi-sensor/model.yamlis therefore flaggeddeprecated: true, and itsexclusive profile
MCLI/AQSORA.1.0.3a_ETSIcarriesdistinction: (deprecated)per theprocedure in
template/README.md#deprecation.We have kept
drivers/aqi-sensor/on purpose: units already deployed on ThingParkstill send uplinks, and deleting the codec would leave those devices undecodable. The
deprecation flag stops new onboarding; please remove the model in a future release once
you are satisfied no active devices depend on it, and we will drop the driver and profile
in a follow-up.
Vendor entry
vendor.yamlnow carries the full company record, and the display name is corrected fromMclimateto MClimate (the brand is capitalised with a capital C).Requests for Actility
co2-sensorandco2-notifierare the same product("CO2 Sensor and Notifier"). They were imported twice, with different
modelIds,different profiles and incompatible field names. Since
modelId/protocolIdareimmutable we have not merged them; instead both now share an identical codec and
consistent metadata. Please advise how to retire one (the catalog documents a
deprecation path for device profiles but not for models). Our preference is to keep
mclimate:co2-notifier:1and deprecatemclimate:co2-sensor:1.LoRaWANCertifiedflags — currentlytrueonly for 16A Dry Switch,Multipurpose Button and Open/Close Sensor; everything else is
false, includingVicki (which has an assigned
lorawanDeviceProfileID03380003). These were filledin bulk from the April 2026 LoRa Alliance list. We would like to reconcile them
against the registry — could you confirm what your import produced?
vendor.yaml— completed: corrected display name (MClimate), full companydescription, website, products page and public contact.
Not in this PR (tracked separately)
extractPoints.jsper driver, to feed ThingPark X IoT Flow "points". Note that theexamples Actility authored already carry
points:blocks for six drivers, which theharness will start asserting as soon as an
extractPoints.jsexists — so this needspointsadded to every uplink example and is best done as its own change.mclimate-payload-helperfound during this work (these are in ourpackage, not in the catalog): the AQI parser returns
NaNafter a refactor; theshared command reader mishandles two Wireless Thermostat responses (
0x56has nobranch,
0x5eis misdecoded as device time); the HT Display Lite parser has the samelux zero-padding bug that ht-sensor had for temperature.
How to verify locally
(Works on macOS too, despite the prerequisites note in
template/sample-vendor/drivers/README.md.)🤖 Generated with Claude Code