Skip to content

Improve CHIP SDK compatibility in Python cluster generator#457

Merged
Apollon77 merged 59 commits intogenerated-python-clientfrom
generated-python-client-chip-similar
Apr 1, 2026
Merged

Improve CHIP SDK compatibility in Python cluster generator#457
Apollon77 merged 59 commits intogenerated-python-clientfrom
generated-python-client-chip-similar

Conversation

@TheJulianJES
Copy link
Copy Markdown
Collaborator

@TheJulianJES TheJulianJES commented Mar 29, 2026

Note: Target branch

This is a PR targeting the branch of the original PR:

This PR is to ease review of the differences compared to that PR and can later be merged into the generated-python-client branch when it's ready.

TODOs

  • The comparison scripts included in this PR should be dropped before it's merged!
    • Lint checks are expected to fail because of this
  • Go through all "key fixes in generator" and see if we actually want them
    • E.g. we may want to include the eventList attribute
  • Go through all "intentionally not changed" notes
  • Go through all "Remaining known differences"
  • Test with Home Assistant Core 
  • ...?

AI summary

Improves the Python cluster generator (generate-python-clusters.ts) to produce definitions that are much more closely aligned with the CHIP SDK's chip.clusters.Objects. A comparison script was used to systematically identify and fix differences across all 121 generated clusters. Fixes were verified by starting Home Assistant with the Matter integration.

Key fixes in the generator

  • Fix list element optionality: The CHIP SDK uses List[Type], not List[Type | None]. List entry types are now resolved via resolveScalarType() directly, skipping optional/nullable wrappers (~183 annotations fixed).
  • Use model.members for command/event fields: Commands and events now use model.members (which includes inherited fields) instead of model.children. This fixes empty WithOnOff commands in LevelControl and ~51 other missing command fields.
  • Fall back to base attribute when local override is an empty stub: Derived clusters (e.g., DishwasherMode from ModeBase) can have local attribute stubs with no type or children that override the base cluster's full definition. Now falls back to the base attribute, fixing supportedModes resolving as List[uint] instead of List[ModeOptionStruct] across all mode clusters.
  • Deduplicate and sort attributes: Attributes are now deduplicated by ID (fixes duplicate minLevel in LevelControl from the Matter.js model) and sorted by tag to match CHIP SDK ordering.
  • Fix multi-bit bitmap masks: The generator only handled single-bit constraints ({"value": 4}1 << 4). Multi-bit fields use range constraints ({"min": 0, "max": 1} → bits 0-1) which fell back to 0x1 instead of the correct mask. Example from Thermostat.HVACSystemTypeBitmap:
    • CoolingStage (bits 0-1): was 0x1, now 0x3
    • HeatingStage (bits 2-3): was 0x1, now 0xC
  • Use metatype as fallback when attribute type is undefined: Attributes with no explicit type but a valid metatype (e.g., float, boolean, string) were all resolving to uint. Now checks metatype first. Fixes EveCluster pressure/voltage/watt/altitude typed as uint instead of float32, and BridgedDeviceBasicInformation vendorName/reachable etc. typed as uint instead of str/bool.
  • Use signed int for temperature, power, energy, voltage types: Builds a SIGNED_INT_TYPES set by walking the Matter.js datatype hierarchy (global + cluster-level) — any type whose base resolves to int8/int16/.../int64 is automatically recognized as signed. No hardcoded type aliases needed. Fixes Thermostat setpoints and calibration values, TemperatureMeasurement, DeviceEnergyManagement power values, and all other signed integer attributes that could have negative values.
  • Remove redundant quotes from type annotations: The generated files use from __future__ import annotations, so explicit quoting (value: 'uint' = 0) is redundant. Now matches CHIP SDK style: value: uint = 0.
  • Remove incorrect GroupId field-name override: CHIP SDK uses groupID (uppercase ID) in most command fields; the previous GroupId: "groupId" override was wrong for the majority of uses.
  • Fix FIELD_NAME_OVERRIDES keys to match Matter.js model names: Override keys must use the raw model name, not the post-toChipName version. Fixes requirePINforRemoteOperation (DoorLock), IPv4Addresses/offPremiseServicesReachableIPv4 (GeneralDiagnostics), extendedPanIdPresent/panIdPresent (ThreadNetworkDiagnostics).
  • Rename objects/ to cluster_defs/: The per-cluster files directory was renamed from objects to cluster_defs to avoid a macOS case-insensitivity collision (objects/ and Objects.py resolved to the same path, causing pylint to read __init__.py instead of Objects.py).
  • Pass clusterName to all generators: toCamelCase and toChipClassName were only receiving clusterName in some generators (cluster-level attributes, enums). Now all generators (structs, commands, events, bitmaps) pass it through, so cluster-qualified overrides in FIELD_NAME_OVERRIDES and CLASS_NAME_OVERRIDES work in all contexts.

CHIP SDK naming compatibility

Added several override mechanisms to match CHIP SDK naming where it diverges from the Matter.js model:

  • CLASS_NAME_OVERRIDES + toChipClassName(): New override map (supports both global and cluster-qualified "Cluster.Name" keys) and helper function for class names where toChipName() doesn't match the CHIP SDK. Applied to all class-name generation sites. Examples:
    • CommissioningARL, AdminVendorId, ICACCSRRequest, ACCapacityformat
    • Enum suffix stripping: WindowCovering.TypeEnumType, WindowCovering.EndProductTypeEnumEndProductType, ModeTagEnumModeTag
    • Bitmap suffix stripping: WindowCovering.ModeBitmapMode, ConfigStatusBitmapConfigStatus, etc.
    • DoorLock legacy names: LockStateEnumDlLockState, LockTypeEnumDlLockType, StatusCodeEnumDlStatus
    • Cluster-specific StatusCode handling: stripped to StatusCode in AdministratorCommissioning/RvcCleanMode/RvcRunMode/TimeSynchronization, kept as StatusCodeEnum elsewhere
    • Custom cluster acronym prevention: DraftElectricalMeasurementCluster uses Ac/Rms (not AC/RMS)
  • K_VALUE_OVERRIDES: Enum/bitmap member name overrides:
    • HueSaturationHueAndSaturation, CredentialOverTheAirAccessCredentialsOverTheAirAccess
    • TiltBlindLiftTiltBlindLiftAndTilt, UnboltingUnbolt
    • LedFeedbackLedFeedback (prevent LED acronym expansion in WindowCovering)
  • FIELD_NAME_OVERRIDES: Additional field name fixes:
    • Lqilqi (CHIP SDK uses lowercase in NetworkCommissioning/ThreadNetworkDiagnostics struct fields)
  • EXTRA_ENUM_MEMBERS: Inject enum members present in the CHIP SDK but missing from the Matter.js model. Used for DoorLock.DlStatus which needs kSuccess, kFailure, kInvalidField, kResourceExhausted, kNotFound.
  • EXTRA_BITMAPS: Inject entire bitmap definitions missing from the Matter.js model. Used for ColorControl.Bitmaps.ColorCapabilitiesBitmap (kHueSaturation, kEnhancedHue, kColorLoop, kXy, kColorTemperature).
  • Cluster-qualified FIELD_NAME_OVERRIDES: toCamelCase() now accepts optional cluster context for cluster-specific field name overrides (e.g., rmsVoltage only in DraftElectricalMeasurementCluster).

Comparison scripts

Added two utility scripts under python_client/scripts/ for verifying compatibility. These are rough developer tools used during this work and can be dropped later:

  • compare_clusters.py: Detailed per-cluster structural comparison between generated and CHIP SDK clusters
  • compare_summary.py: Categorized summary of systematic differences (detects case, Enum suffix, and Bitmap suffix mismatches)

Intentionally not changed

These differences from the older CHIP SDK were identified but deliberately kept as-is, since the generated output is more correct or forward-compatible:

  • eventList global attribute: The CHIP SDK version doesn't include eventList (tag 0xFFFA), but it is part of the Matter spec and newer CHIP SDK versions include it. Kept.
  • kUnknownEnumValue calculation: The older CHIP SDK sometimes uses 0, but the current approach (first unused value after the max defined value) avoids assigning semantically meaningful low values. Kept.
  • Bitmap types in annotations: The older CHIP SDK uses plain uint for bitmap-typed fields, but using the actual bitmap type (e.g., OptionsBitmap) is more type-safe. Kept.

Issues to fix upstream in Matter.js

These are data gaps or bugs in the Matter.js model that required workarounds in the generator. Fixing them upstream would allow removing the corresponding overrides:

  • Duplicate MinLevel attribute in LevelControl: The model defines MinLevel (id 2) twice — once for the Lighting conformance variant and once for non-Lighting. The generator deduplicates by ID, but the model should only expose one.
  • Empty attribute stubs in derived clusters: Clusters derived from a base (e.g., DishwasherMode from ModeBase) have local attribute stubs with no type or children that shadow the base definition. This caused supportedModes to lose its List[ModeOptionStruct] type. The generator now falls back to the base, but ideally the model would inherit the full definition.
  • Missing ColorCapabilitiesBitmap in ColorControl: The CHIP SDK defines this bitmap but it's absent from the Matter.js model. Currently injected via EXTRA_BITMAPS.
  • Missing DlStatus enum members in DoorLock: The StatusCodeEnum only has Duplicate and Occupied, but the CHIP SDK's DlStatus also includes kSuccess, kFailure, kInvalidField, kResourceExhausted, kNotFound. Currently injected via EXTRA_ENUM_MEMBERS.
  • TiltBlindLift naming in WindowCovering.TypeEnum: Matter.js uses TiltBlindLift (value 8) but the CHIP SDK calls it TiltBlindLiftAndTilt. Currently handled via K_VALUE_OVERRIDES.
  • Unbolting naming in DoorLock Feature bitmap: Matter.js uses Unbolting but the CHIP SDK uses Unbolt. Currently handled via K_VALUE_OVERRIDES.
  • Attributes with undefined type but valid metatype: Custom cluster attributes (e.g., EveCluster pressure, voltage, altitude) and some inherited attributes (BridgedDeviceBasicInformation vendorName, reachable) have type: undefined in the model. The generator now falls back to metatype (float → float32, string → str, boolean → bool), but ideally the model would set the type field explicitly.
  • Channel.ProgramStruct.externalIDList wrong struct reference: Matter.js references ContentLauncher.AdditionalInfoStruct but CHIP SDK uses Channel.ProgramCastStruct. Cross-cluster reference issue in the model.
  • Descriptor.tagList uses Globals.Structs.semtag: CHIP SDK uses Descriptor.Structs.SemanticTagStruct. The struct is defined globally in Matter.js but locally in the CHIP SDK.
  • IlluminanceMeasurement.lightSensorType resolves to uint: Should be LightSensorTypeEnum but the enum reference isn't resolved. Model-level type resolution issue.
  • ContentAppObserver.ContentAppMessage data/encodingHint optionality swapped: data is optional in CHIP SDK but mandatory in generated; encodingHint is the reverse. Conformance mismatch in the model.

Issues to address in HA

  • Pylint E0611 (no-name-in-module) for chip.clusters.Objects: Now resolved by renaming the per-cluster directory from objects/ to cluster_defs/, which eliminates the macOS case-insensitivity collision that caused pylint to read objects/__init__.py instead of Objects.py.

Remaining known differences (not fixable at generator level)

  • Module path differences (~284): Expected from the split-file architecture (chip.clusters.cluster_defs.X.X vs chip.clusters.Objects.X)
  • aenum vs enum (~189): Inherent difference in MatterIntEnum base class between CHIP SDK and our implementation
  • Spec version differences: Some enums/bitmaps/structs/commands exist in only one side due to different Matter spec versions between Matter.js and the CHIP SDK
  • Optionality mismatches (~79 total across descriptors, commands, structs, events): Some fields are optional in CHIP SDK but mandatory in generated (or vice versa), due to conformance differences in the Matter.js model vs CHIP SDK. Notable: BridgedDeviceBasicInformation fields, mode cluster statusText, MediaPlayback trackAttributes nullability.
  • Cross-cluster struct references: Matter.js resolves some structs from different clusters than the CHIP SDK (e.g., Channel.ProgramStruct.externalIDList references ContentLauncher.AdditionalInfoStruct instead of Channel.ProgramCastStruct; Descriptor.tagList uses Globals.Structs.semtag instead of Descriptor.Structs.SemanticTagStruct)
  • Field name casing (a few remaining): GroupKeyManagement.groupId vs groupID, ThreadNetworkDirectory.extendedPanId vs extendedPanID — trade-offs where the override benefits the majority of uses

Test plan

  • Generator runs without errors (npx tsx python_client/scripts/generate-python-clusters.ts)
  • Comparison script confirms 0 duplicate fields, 0 name mismatches
  • LevelControl cluster matches CHIP SDK structurally (verified manually)
  • HA Matter integration loads without import errors (WindowCovering, DoorLock, DraftElectricalMeasurementCluster, ElectricalPowerMeasurement, device_types verified)
  • Mode cluster supportedModes correctly typed as List[ModeOptionStruct] (DishwasherMode, RvcRunMode, etc.)
  • EveCluster float attributes (pressure, voltage, etc.) correctly typed as float32
  • Temperature/power/energy attributes correctly typed as int (Thermostat, TemperatureMeasurement, DeviceEnergyManagement)
  • Pylint E0611 resolved after objects/cluster_defs/ rename
  • DoorLock requirePINforRemoteOperation field name correct (lowercase for)
  • GeneralDiagnostics IPv4Addresses/offPremiseServicesReachableIPv4 field names correct
  • Thermostat calibration/deadband/changeAmount correctly typed as int (signed)
  • NetworkCommissioning/ThreadNetworkDiagnostics lqi field name correct (lowercase)
  • WindowCovering kLedFeedback bitmap member correct (not kLEDFeedback)
  • Full comparison run: 0 duplicate fields, 0 name mismatches, 0 empty commands
  • Filtered comparison: 284 remaining differences are all model-level (optionality, spec version, cross-cluster references)
  • Full HA integration test with commissioned devices

Systematically align generated output with CHIP SDK's chip.clusters.Objects:

- Remove eventList global attribute (not in CHIP SDK)
- Use uint for bitmap-typed fields (CHIP SDK convention)
- Fix list element types to not wrap in Optional/Nullable
- Fix kUnknownEnumValue to use first unused value from 0
- Use model.members for command/event fields (includes inherited)
- Deduplicate and sort attributes by tag ID
- Fix multi-bit bitmap masks for range constraints
- Add CLASS_NAME_OVERRIDES + toChipClassName() for naming edge cases
- Add K_VALUE_OVERRIDES for bitmap member name mismatches
- Remove incorrect GroupId field-name override

Also adds comparison utility scripts (compare_clusters.py,
compare_summary.py) for verifying CHIP SDK compatibility.
Adds compare_clusters.py and compare_summary.py for verifying CHIP SDK compatibility
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The generated files use `from __future__ import annotations` which
already makes all annotations strings, so explicit quoting is redundant.
Matches CHIP SDK style: `value: uint = 0` instead of `value: 'uint' = 0`.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
eventList is part of the Matter spec and newer CHIP SDK versions include
it. kUnknownEnumValue as first-unused-after-max avoids assigning
semantically meaningful low values like 0.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Using the actual bitmap type (e.g., OptionsBitmap) is more type-safe
than plain uint, even though the older CHIP SDK uses uint.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The CHIP SDK omits the "Enum" suffix for some enum class names
(e.g., WindowCovering.Enums.Type not TypeEnum). Add CLASS_NAME_OVERRIDES
for Type, EndProductType, ModeTag, StatusCode, SelectAreasStatus,
and SkipAreaStatus.

Fixes HA crash: AttributeError: type object 'Enums' has no attribute 'Type'
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Make toChipClassName() accept optional cluster context to support
cluster-qualified overrides (e.g., "AdministratorCommissioning.StatusCodeEnum"
→ "StatusCode" while ValveConfigurationAndControl keeps "StatusCodeEnum").

Also strip Bitmap suffix for WindowCovering bitmaps (Mode, ConfigStatus,
OperationalStatus, SafetyStatus) to match CHIP SDK.

Improve compare_summary.py to detect Enum/Bitmap suffix mismatches.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Matter.js uses TiltBlindLift but the CHIP SDK (and HA) expects
kTiltBlindLiftAndTilt for WindowCovering.Enums.Type value 8.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The CHIP SDK uses legacy "Dl" prefixed names for three DoorLock enums
that differ from the Matter.js model names (LockStateEnum, LockTypeEnum,
StatusCodeEnum). HA references these legacy names.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The Matter.js model only has 2 members (Duplicate, Occupied) while the
CHIP SDK's DlStatus has 7 (including kSuccess, kFailure, etc.). Renaming
would expose an incomplete enum that crashes HA.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The Matter.js model only defines 2 members for DoorLock.StatusCodeEnum
(Duplicate, Occupied) but the CHIP SDK's DlStatus has 7 including
kSuccess, kFailure, kInvalidField, kResourceExhausted, and kNotFound.

Add EXTRA_ENUM_MEMBERS mechanism to inject additional enum members that
are present in the CHIP SDK but missing from the Matter.js model.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Custom cluster uses "Ac" not "AC" in attribute names (e.g., AcPowerDivisor
not ACPowerDivisor). Add CLASS_NAME_OVERRIDES and FIELD_NAME_OVERRIDES.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Custom cluster uses "Rms" not "RMS" (e.g., RmsVoltage not RMSVoltage).
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
The DraftElectricalMeasurementCluster custom cluster uses "Rms"/"rms"
while standard clusters like ElectricalPowerMeasurement use "RMS".
Use cluster-qualified keys in both FIELD_NAME_OVERRIDES and
CLASS_NAME_OVERRIDES, and add clusterName parameter to toCamelCase().
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
@TheJulianJES
Copy link
Copy Markdown
Collaborator Author

HA uses DoorLock.Enums.DlStatus (here), but this does not appear to exist in Matter.js on a cluster-level, from what I can see. The generated Python definitions from the CHIP SDK for reference:

@dataclass
class DoorLock(Cluster):
    # [...]
    class Enums:

        # [...]
        class DlStatus(MatterIntEnum):
            kSuccess = 0x00
            kFailure = 0x01
            kDuplicate = 0x02
            kOccupied = 0x03
            kInvalidField = 0x85
            kResourceExhausted = 0x89
            kNotFound = 0x8B
            # All received enum values that are not listed above will be mapped
            # to kUnknownEnumValue. This is a helper enum value that should only
            # be used by code to process how it handles receiving an unknown
            # enum value. This specific value should never be transmitted.
            kUnknownEnumValue = 4

We may need to use the generic status codes in HA(?)

export const MatterStatusNames: Record<number, string> = {
0: "Success",
1: "Failure",
125: "InvalidSubscription",
126: "UnsupportedAccess",
127: "UnsupportedEndpoint",
128: "InvalidAction",
129: "UnsupportedCommand",
133: "InvalidCommand",
134: "UnsupportedAttribute",
135: "ConstraintError",
136: "UnsupportedWrite",
137: "ResourceExhausted",
139: "NotFound",
140: "UnreportableAttribute",
141: "InvalidDataType",
143: "UnsupportedRead",
146: "DataVersionMismatch",
148: "Timeout",
155: "UnsupportedNode",
156: "Busy",
157: "AccessRestricted",
195: "UnsupportedCluster",
197: "NoUpstreamSubscription",
198: "NeedsTimedInteraction",
199: "UnsupportedEvent",
200: "PathsExhausted",
201: "TimedRequestMismatch",
202: "FailsafeRequired",
203: "InvalidInState",
204: "NoCommandResponse",
205: "TermsAndConditionsChanged",
206: "MaintenanceRequired",
207: "DynamicConstraintError",
208: "AlreadyExists",
209: "InvalidTransportType",
};

I'll add them as hardcoded values to the generator for now, just so I can further test what else breaks HA.

@TheJulianJES
Copy link
Copy Markdown
Collaborator Author

TheJulianJES commented Mar 29, 2026

  • Remove chip-clusters dependency and auto generate API compatible classes  #303 not only modifies the CHIP cluster definitions but matter_server models as well, like device types. These are incompatible as well.
    • We should either drop them for that PR or fix them here as well.
      • I'll try to fix them here as well for now, so I can continue testing.
      • It would be cleaner to maybe have those auto-generation changes in another PR though.
    • E.g. HeatingCoolingUnit seems to be missing completely now (used by HA here)
      • Does this even exist in Matter.js?
    • There also appear to be other unrelated changes in that PR to matter_server that seem like weird AI generations, e.g. why is a separate msg str for every exception created before now?

EDIT: The HeatingCoolingUnit does not actually seem to exist, so it should be removed from HA. I'll do that later.

The original hand-maintained device_types.py included HeatingCoolingUnit
(0x0300) which HA references, but it's not in the Matter.js model.
Add it as an extra device type in the generator.
Replace wildcard import with explicit per-cluster imports in Objects.py.
This eliminates all indirection — Objects.py is the single source of
truth for all exports (clusters, base classes, primitives). The
_cluster_defs/__init__.py is now empty (only needed for relative imports
in per-cluster files). No wildcard imports means better static analysis.
Drop the underscore prefix — the package is imported directly by
custom_clusters.py and tests, so it's not truly private.
@TheJulianJES
Copy link
Copy Markdown
Collaborator Author

TheJulianJES commented Mar 30, 2026

Other differences to look at later:
EDIT: Some fixed. PR description updated now.


Critical (would cause wrong values or crashes in HA):

  1. Temperature fields as uint instead of int — Thermostat setpoints, TemperatureMeasurement. Negative temperatures would be wrong. This affects the metatype: "integer" fallback — when type is undefined, signed integers also default to uint.
  2. DeviceEnergyManagement/ElectricalEnergyMeasurement signed int vs uint — Power/energy values that can be negative.
  3. BridgedDeviceBasicInformation optionality inversions — Fields mandatory in Gen but optional in CHIP (would crash if device doesn't provide them).
  4. Mode clusters statusText mandatory vs optional — Across all mode clusters.
  5. MediaPlayback TrackStruct.trackAttributes lost nullability — Would crash on null.

Field name mismatches (could cause attribute lookup failures):

  1. GeneralDiagnostics IPv4Addresses vs IPV4Addresses — We have FIELD_NAME_OVERRIDES but they may not be applied to struct field contexts.
  2. GroupKeyManagement groupId vs groupID — Known trade-off.
  3. DoorLock requirePINforRemoteOperation — We have override, may not apply everywhere.
  4. ThreadNetworkDirectory extendedPanID vs extendedPanId

Structural issues:

  1. Channel ProgramStruct.externalIDList — References wrong cluster struct (ContentLauncher.AdditionalInfoStruct instead of ProgramCastStruct)
  2. Descriptor tagList — Uses Globals.Structs.semtag instead of Descriptor.Structs.SemanticTagStruct
  3. WindowCovering commands have extra ignored field

The generator mapped all integer types to uint, but semantic type aliases
like temperature (int16), power-mW (int64), energy-mWh (int64), etc.
are signed. Add these aliases to resolvePrimitiveByName and delegate
the metatype "integer" case to it so both code paths resolve correctly.

Fixes Thermostat setpoints, TemperatureMeasurement, DeviceEnergyManagement
power values, and all other signed integer attributes.
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Override keys must use the raw Matter.js model name, not the
post-toChipName version. Fixes:
- RequirePinForRemoteOperation (was RequirePINForRemoteOperation)
- IPv4Addresses (was Ipv4Addresses)
- OffPremiseServicesReachableIPv4/IPv6 (was ...IPV4/IPV6)
- ExtendedPanIdPresent/PanIdPresent (was ...PanIDPresent)
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
- Add SignedTemperature and TemperatureDifference to signed int aliases
  (fixes localTemperatureCalibration, minSetpointDeadBand, setpointChangeAmount)
- Add FIELD_NAME_OVERRIDE Lqi → lqi (CHIP SDK uses lowercase)
- Add K_VALUE_OVERRIDE LedFeedback → LedFeedback (prevent LED expansion)
Output of running: npx tsx python_client/scripts/generate-python-clusters.ts
Build SIGNED_INT_TYPES set by walking the Matter.js datatype hierarchy
(global + cluster-level) instead of hardcoding type aliases. Any type
whose base resolves to int8/int16/.../int64 is automatically recognized.
@TheJulianJES TheJulianJES force-pushed the generated-python-client-chip-similar branch from d57f971 to 546f895 Compare March 30, 2026 00:53
- Pass clusterName to toCamelCase in generateStruct, generateCommand,
  generateEvent (fixes cluster-qualified FIELD_NAME_OVERRIDES not matching)
- Pass clusterName to toChipClassName in generateStruct, generateCommand,
  generateEvent, generateBitmap (fixes cluster-qualified CLASS_NAME_OVERRIDES)
- Pass "Globals" to generateEnum in generateGlobalsFile for consistency
- Remove identical if/else branches in resolvePythonType and attribute
  field generation
The compare_clusters.py and compare_summary.py scripts were developer
tools used during this work. Removed from git but kept locally.
mypy cannot resolve names re-exported via wildcard imports. Add a
complete __all__ listing all cluster names plus base classes and
primitive types so mypy sees them as explicit exports.

Fixes 11 mypy errors (name-defined, attr-defined) in node.py,
test_imports.py, and test_integration.py.
deviceTypeList is typed as List[DeviceTypeStruct] (not Optional), so
elements are never None. mypy correctly flags the check as unreachable.
Comment thread python_client/scripts/generate-python-clusters.ts
Comment thread python_client/scripts/generate-python-clusters.ts Outdated
No longer needed — removed the hardcoded HeatingCoolingUnit (0x0300)
device type and the extra device types injection mechanism.
The generated GeneralDiagnostics cluster uses IPv4Addresses/IPv6Addresses
(matching CHIP SDK), not iPv4Addresses/iPv6Addresses.
The generated NetworkCommissioning cluster uses LastNetworkID (uppercase
ID from acronym expansion), not LastNetworkId.
- client.py: simplify `f.label if f.label else None` → `f.label or None`
- node.py: add maxsplit=1 to split() when only first element is used
@TheJulianJES TheJulianJES force-pushed the generated-python-client-chip-similar branch from 21495b7 to 7ad0ed6 Compare April 1, 2026 15:32
@TheJulianJES TheJulianJES marked this pull request as ready for review April 1, 2026 15:38
@Apollon77 Apollon77 merged commit 2e50679 into generated-python-client Apr 1, 2026
6 checks passed
@Apollon77 Apollon77 deleted the generated-python-client-chip-similar branch April 1, 2026 21:57
Apollon77 added a commit that referenced this pull request Apr 15, 2026
…ses (#303)

* Replace home-assistant-chip-clusters with generated code from Matter.js model

Generate Python cluster definitions directly from MatterModel.standard,
eliminating the dependency on home-assistant-chip-clusters and aenum.

Changes:
- Add python_client/chip/ package with hand-written infrastructure:
  - ChipUtility.py: classproperty descriptor
  - tlv/: uint, float32, TLVWriter, TLVReader
  - clusters/ClusterObjects.py: base classes + ALL_* registration dicts
  - clusters/Types.py: Nullable, NullValue
  - clusters/enum.py: MatterIntEnum (stdlib IntEnum, no aenum)
- Add generator script python_client/scripts/generate-python-clusters.ts
  - Reads MatterModel.standard and generates 121 cluster files
  - One file per cluster in chip/clusters/objects/
  - Objects.py re-exports all clusters for API compatibility
  - Also generates device_types.py from Matter.deviceTypes
- Remove home-assistant-chip-clusters and aenum from pyproject.toml
- Add dacite as explicit dependency (was transitive via chip-clusters)
- Include chip* in setuptools package discovery
- Add python:generate npm script

All 12 Python unit tests pass. All 228 JS tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix generator compatibility: derived clusters and acronym casing

- Resolve cluster inheritance: derived clusters (ModeBase, OperationalState,
  ConcentrationMeasurement, ResourceMonitoring, AlarmBase, Label) now inherit
  all base cluster members (datatypes, commands, attributes, events)
- Handle command direction override: when derived cluster overrides a base
  command without specifying direction, use the base command's metadata
- Preserve chip-clusters acronym casing: OTA, DST, UTC, NTP, CO, EV, CEC,
  URL, PIN, ACL, ICAC, CSR, NOC, TC, VID, LED, RFID are kept uppercase
  (e.g., AddNOC not AddNoc, SetDSTOffset not SetDstOffset)
- Register inherited datatypes in the datatype registry for cross-references

Result: 0 differences across all 121 common clusters when compared with
the original home-assistant-chip-clusters package.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix missing Globals import in generated cluster files

Clusters referencing global types (e.g., Globals.Enums.enum8) failed at
runtime with NameError because the generator excluded 'Globals' from
cross-cluster imports. Remove the Globals exclusion so it is imported
like any other cross-cluster reference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Mark generated Python files in .gitattributes

Mark auto-generated cluster files, Objects.py, and device_types.py as
linguist-generated=true to collapse them in GitHub PR diffs for easier
review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix generator trailing newlines in Python files

Each generated Python file now ends with exactly one newline (PEP 8).

Previously, loops added blank lines after every element including the
last one, resulting in two trailing newlines. Changed all element loops
to only add blank lines between elements, not after the last one.

Affected: cluster files (Enums, Bitmaps, Structs, Commands, Attributes,
Events sections) and device_types.py.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add TypeScript config for Python scripts directory

Created tsconfig.json for python_client/scripts/ with proper module
resolution (node16) and type definitions. This enables IDE support and
type checking for the code generator script.

Also cleaned up unused imports and parameters in the generator to pass
strict TypeScript checks (noUnusedLocals, noUnusedParameters).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove unnecessary type assertion in generator

Removed '!' assertion on dt.id since TypeScript already knows it's
defined after filtering for !== undefined.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix acronym casing in field names - add ID to acronym list

Added 'ID' to the acronym list to ensure field names like vendorId,
fabricId, nodeId get properly transformed to vendorID, fabricID, nodeID
(matching chip-clusters behavior).

Also updated toCamelCase() to apply acronym preservation before
lowercasing the first character, ensuring camelCase field names like
vendorID (not vendorId) match the original chip-clusters API.

Reordered ACRONYMS list to process longer acronyms first to avoid
over-matching (e.g., VID before ID).

All 75 Python tests now pass including full integration tests against
real Matter.js server.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add Python linting and type checking tools

- Add ruff, mypy, pylint configuration matching python-matter-server standards
- Configure comprehensive ruff rule set with appropriate ignores for generated code
- Add mypy strict type checking with overrides for generated files and tests
- Fix field name casing bugs: iPv4Addresses/iPv6Addresses, LastNetworkId
- Fix exception handling in connection.py to avoid type pollution
- Add npm scripts for python:lint, python:lint-fix, python:typecheck
- Update generator to add __all__ export list for type checkers
- Update generator to fix docstring formatting (PEP 257)
- Update generator to add type hint for __init_subclass__
- Generated code properly excluded from all linting/type checks
- All 75 Python tests passing
- Ruff: 0 errors (218 auto-fixes applied)
- Mypy: 5 errors (all in tests, matching python-matter-server pattern)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add Python linting and type checking to CI

- Add new 'lint' job that runs before unit and integration tests
- Run ruff linter on python_client (excluding generated chip/ directory)
- Run mypy type checker on python_client
- Both unit-tests and integration-tests now depend on lint job passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix mypy CI configuration path issue

Run ruff and mypy from within python_client directory so they pick up
pyproject.toml configuration correctly. This ensures generated code in
chip/ is properly excluded.

Fixes: Found 3701 errors → 5 errors (only in tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix remaining mypy errors

- Add None check for process.stdout in test helper
- Add None check for dev_info before accessing deviceType
- Add assertion for client.server_info before accessing schema_version
- Add return type annotation for _onoff_command helper
- Add TYPE_CHECKING import for Clusters type hint
- Add type ignore for aiohttp ClientWSTimeout deprecation

Result: All mypy checks passing (0 errors in 157 files)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR #303 code quality review comments

1. Add missing comparison methods to Nullable class (__le__, __gt__, __ge__)
   to complete ordering protocol. Maintains consistent behavior where Nullable
   compares as less-than-or-equal to everything.

2. Remove unnecessary pass statements from generated command classes with no
   fields. The descriptor method is already present, so pass is redundant.

All tests passing. Addresses github-code-quality bot feedback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Review feedback and updates

* Improve Python cluster drop-in compatibility with chip-clusters package

- Revert classproperty caching (PR reviewer request)
- Add uint, NullValue, Nullable, float32 re-exports to chip.clusters.Objects
- Expand ACRONYMS list in generator (~30 new entries, correct ordering)
- Fix toKName() to apply acronym expansion for compound k-values (kProgrammingPIN etc.)
- Add K_VALUE_OVERRIDES map for k-values chip-clusters keeps in TitleCase (kPin, kRfid, etc.)
- Add EventList (0xFFFA) as a generated global attribute on all clusters
- Remove spurious pass statements from generateStruct and generateEvent
- Strip Enum suffix from enum class names only in registry lookup (not class names)
- Add meaningful type assertions in test_imports.py for re-exported primitives
- Reduce naming mismatches vs home-assistant-chip-clusters from 581 to ~349
  (remaining are Matter spec version differences between 1.4 and 1.2/1.3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: correct misleading comments in generate-python-clusters.ts

- ACRONYMS comment now accurately states that ordering IS required
  (SNTP before NTP, UTC before TC, PIN before PI) because shorter
  forms are suffixes of longer ones
- Add omission comment for ACL alongside ARL explanation
- stripEnumSuffix comment now clarifies it is for registry aliases only;
  old chip-clusters (≤2024.11.4) KEEPS the Enum suffix in class names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: kRollerShade casing in WindowCovering.TypeEnum

matter.js models these as one-word "rollershade*" but chip SDK
treats it as two words "RollerShade*". Add 4 K_VALUE_OVERRIDES
entries to produce the correct kRollerShade, kRollerShade2Motor,
kRollerShadeExterior, kRollerShadeExterior2Motor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: correct field-name casing to match chip-clusters 2024.11.4

- toCamelCase now preserves leading acronyms (ESAType, ACCapacity, UTCTime, etc.)
- Add FIELD_NAME_OVERRIDES for chip SDK inconsistencies (panId vs panID, etc.)
- Add PAKE, IPK, LQI, URI to ACRONYMS list
- BX/BY/GX/GY/RX/RY omitted from ACRONYMS (too broad — "ByNumber" regression)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add ColorPoint coordinate FIELD_NAME_OVERRIDES (colorPointBX etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: clarify FIELD_NAME_OVERRIDES comments and verify ACCapacityformat casing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: emit must_use_timed_invoke for timed commands

Commands with access.timed=true in the Matter.js model now emit the
@ChipUtility.classproperty must_use_timed_invoke → True property,
matching the old chip-clusters SDK convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: use model.members in generateStruct to include inherited fields

ModeOptionStruct in mode clusters (DishwasherMode, OvenMode, RvcCleanMode, etc.)
defines zero direct children but inherits label/mode/modeTags from the global
base struct. Switching from model.children to model.members picks up these
inherited fields and generates correct Python dataclasses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add _require_state guard to skip dependent integration tests

When an early integration test fails (e.g. commissioning), subsequent
tests that depend on node_id/test_node_id would fail with confusing
errors instead of cleanly skipping. This helper surfaces the real failure
without masking it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: avoid mypy attr-defined error in test_mode_option_struct_has_fields

The loop over (DishwasherMode, OvenMode) caused mypy to infer cls as
type[Cluster], which has no Structs attribute. Replace with direct calls
to a helper function, keeping type information concrete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: type _assert_mode_option_struct_fields param as Any for mypy

struct: type caused attr-defined on __dataclass_fields__ since mypy
doesn't know plain type objects carry dataclass metadata.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve CHIP SDK compatibility in Python cluster generator (#457)

* fix: improve CHIP SDK compatibility in Python cluster generator

Systematically align generated output with CHIP SDK's chip.clusters.Objects:

- Remove eventList global attribute (not in CHIP SDK)
- Use uint for bitmap-typed fields (CHIP SDK convention)
- Fix list element types to not wrap in Optional/Nullable
- Fix kUnknownEnumValue to use first unused value from 0
- Use model.members for command/event fields (includes inherited)
- Deduplicate and sort attributes by tag ID
- Fix multi-bit bitmap masks for range constraints
- Add CLASS_NAME_OVERRIDES + toChipClassName() for naming edge cases
- Add K_VALUE_OVERRIDES for bitmap member name mismatches
- Remove incorrect GroupId field-name override

Also adds comparison utility scripts (compare_clusters.py,
compare_summary.py) for verifying CHIP SDK compatibility.

* feat: Add comparison utility scripts

Adds compare_clusters.py and compare_summary.py for verifying CHIP SDK compatibility

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: remove redundant quotes from type annotations

The generated files use `from __future__ import annotations` which
already makes all annotations strings, so explicit quoting is redundant.
Matches CHIP SDK style: `value: uint = 0` instead of `value: 'uint' = 0`.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* revert: keep eventList attribute and kUnknownEnumValue after-max logic

eventList is part of the Matter spec and newer CHIP SDK versions include
it. kUnknownEnumValue as first-unused-after-max avoids assigning
semantically meaningful low values like 0.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* revert: keep bitmap types instead of replacing with uint

Using the actual bitmap type (e.g., OptionsBitmap) is more type-safe
than plain uint, even though the older CHIP SDK uses uint.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: strip Enum suffix from class names where CHIP SDK omits it

The CHIP SDK omits the "Enum" suffix for some enum class names
(e.g., WindowCovering.Enums.Type not TypeEnum). Add CLASS_NAME_OVERRIDES
for Type, EndProductType, ModeTag, StatusCode, SelectAreasStatus,
and SkipAreaStatus.

Fixes HA crash: AttributeError: type object 'Enums' has no attribute 'Type'

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: cluster-aware class name overrides for Enum/Bitmap suffix stripping

Make toChipClassName() accept optional cluster context to support
cluster-qualified overrides (e.g., "AdministratorCommissioning.StatusCodeEnum"
→ "StatusCode" while ValveConfigurationAndControl keeps "StatusCodeEnum").

Also strip Bitmap suffix for WindowCovering bitmaps (Mode, ConfigStatus,
OperationalStatus, SafetyStatus) to match CHIP SDK.

Improve compare_summary.py to detect Enum/Bitmap suffix mismatches.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: rename TiltBlindLift to TiltBlindLiftAndTilt for CHIP SDK compat

Matter.js uses TiltBlindLift but the CHIP SDK (and HA) expects
kTiltBlindLiftAndTilt for WindowCovering.Enums.Type value 8.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: use legacy DoorLock enum names (DlLockState, DlLockType, DlStatus)

The CHIP SDK uses legacy "Dl" prefixed names for three DoorLock enums
that differ from the Matter.js model names (LockStateEnum, LockTypeEnum,
StatusCodeEnum). HA references these legacy names.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: don't rename DoorLock.StatusCodeEnum to DlStatus

The Matter.js model only has 2 members (Duplicate, Occupied) while the
CHIP SDK's DlStatus has 7 (including kSuccess, kFailure, etc.). Renaming
would expose an incomplete enum that crashes HA.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: add missing DlStatus enum members via EXTRA_ENUM_MEMBERS

The Matter.js model only defines 2 members for DoorLock.StatusCodeEnum
(Duplicate, Occupied) but the CHIP SDK's DlStatus has 7 including
kSuccess, kFailure, kInvalidField, kResourceExhausted, and kNotFound.

Add EXTRA_ENUM_MEMBERS mechanism to inject additional enum members that
are present in the CHIP SDK but missing from the Matter.js model.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: prevent AC acronym expansion for DraftElectricalMeasurementCluster

Custom cluster uses "Ac" not "AC" in attribute names (e.g., AcPowerDivisor
not ACPowerDivisor). Add CLASS_NAME_OVERRIDES and FIELD_NAME_OVERRIDES.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: prevent RMS acronym expansion for DraftElectricalMeasurementCluster

Custom cluster uses "Rms" not "RMS" (e.g., RmsVoltage not RMSVoltage).

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: make Rms field/class overrides cluster-specific

The DraftElectricalMeasurementCluster custom cluster uses "Rms"/"rms"
while standard clusters like ElectricalPowerMeasurement use "RMS".
Use cluster-qualified keys in both FIELD_NAME_OVERRIDES and
CLASS_NAME_OVERRIDES, and add clusterName parameter to toCamelCase().

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: add HeatingCoolingUnit device type missing from Matter.js model

The original hand-maintained device_types.py included HeatingCoolingUnit
(0x0300) which HA references, but it's not in the Matter.js model.
Add it as an extra device type in the generator.

* fix: rename kUnbolting to kUnbolt for DoorLock Feature bitmap

Matter.js uses "Unbolting" but the CHIP SDK (and HA) expects "kUnbolt".

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: use base cluster attribute type when local override is an empty stub

Derived clusters (e.g., DishwasherMode from ModeBase) can have local
attribute stubs with no type or children. These stubs overrode the base
cluster's full definition, causing supportedModes to resolve as List[uint]
instead of List[ModeOptionStruct].

Now falls back to the base attribute when the local one has no type.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: add ColorCapabilitiesBitmap missing from Matter.js model

The CHIP SDK has ColorControl.Bitmaps.ColorCapabilitiesBitmap but it's
not in the Matter.js model. Add EXTRA_BITMAPS mechanism to inject
bitmap definitions and use it for ColorCapabilitiesBitmap.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: use metatype as fallback when attribute type is undefined

Attributes with no explicit type (type=undefined) but a valid metatype
(e.g., float, boolean, string) were all resolving to uint. Now checks
metatype before falling back to uint.

Fixes EveCluster pressure/voltage/watt/altitude typed as uint instead
of float32, and BridgedDeviceBasicInformation fields typed as uint
instead of str/bool.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: use explicit assignments in Objects.py for pylint compatibility

Pylint cannot resolve names re-exported via 'from ... import' and
reports E0611 (no-name-in-module) for ClusterCommand, NullValue, uint,
etc. Use explicit assignments (e.g., Cluster = _co.Cluster) so pylint
sees them as concrete module-level names.

* fix: move base class exports into objects/__init__.py for pylint compat

On macOS (case-insensitive FS), chip/clusters/Objects and
chip/clusters/objects resolve to the same path, so pylint/astroid
reads objects/__init__.py instead of Objects.py. Move base class
and primitive type assignments (Cluster, ClusterCommand, NullValue,
uint, etc.) into objects/__init__.py so they're visible to pylint
on all platforms.

Objects.py becomes a thin re-export for case-sensitive filesystems.

* fix: rename objects/ to _cluster_defs/ to avoid macOS case collision

On macOS (case-insensitive FS), chip/clusters/objects/ and
chip/clusters/Objects.py resolve to the same path, causing pylint
to read __init__.py instead of Objects.py. Renaming the directory
to _cluster_defs/ eliminates the collision entirely.

Objects.py is now a thin re-export from chip.clusters._cluster_defs.
_cluster_defs/__init__.py contains base classes, primitives, and all
cluster imports. HA imports are unaffected (they use chip.clusters.Objects).

* refactor: simplify Objects.py and _cluster_defs/__init__.py

Now that the objects/ → _cluster_defs/ rename eliminates the macOS
case collision, the explicit assignment workaround in __init__.py is
unnecessary. Restore simple structure:
- _cluster_defs/__init__.py: just cluster imports
- Objects.py: re-exports clusters + base classes + primitives

* refactor: use explicit imports in Objects.py, empty __init__.py

Replace wildcard import with explicit per-cluster imports in Objects.py.
This eliminates all indirection — Objects.py is the single source of
truth for all exports (clusters, base classes, primitives). The
_cluster_defs/__init__.py is now empty (only needed for relative imports
in per-cluster files). No wildcard imports means better static analysis.

* Revert "refactor: use explicit imports in Objects.py, empty __init__.py"

This reverts commit aaf807e.

* refactor: rename _cluster_defs to cluster_defs

Drop the underscore prefix — the package is imported directly by
custom_clusters.py and tests, so it's not truly private.

* fix: use signed int for temperature, power, energy, voltage types

The generator mapped all integer types to uint, but semantic type aliases
like temperature (int16), power-mW (int64), energy-mWh (int64), etc.
are signed. Add these aliases to resolvePrimitiveByName and delegate
the metatype "integer" case to it so both code paths resolve correctly.

Fixes Thermostat setpoints, TemperatureMeasurement, DeviceEnergyManagement
power values, and all other signed integer attributes.

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: correct FIELD_NAME_OVERRIDES keys to match Matter.js model names

Override keys must use the raw Matter.js model name, not the
post-toChipName version. Fixes:
- RequirePinForRemoteOperation (was RequirePINForRemoteOperation)
- IPv4Addresses (was Ipv4Addresses)
- OffPremiseServicesReachableIPv4/IPv6 (was ...IPV4/IPV6)
- ExtendedPanIdPresent/PanIdPresent (was ...PanIDPresent)

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* fix: Thermostat signed types, lqi field name, kLedFeedback casing

- Add SignedTemperature and TemperatureDifference to signed int aliases
  (fixes localTemperatureCalibration, minSetpointDeadBand, setpointChangeAmount)
- Add FIELD_NAME_OVERRIDE Lqi → lqi (CHIP SDK uses lowercase)
- Add K_VALUE_OVERRIDE LedFeedback → LedFeedback (prevent LED expansion)

* chore: regenerate Python cluster definitions

Output of running: npx tsx python_client/scripts/generate-python-clusters.ts

* refactor: resolve signed int types from Matter.js model, not hardcoded

Build SIGNED_INT_TYPES set by walking the Matter.js datatype hierarchy
(global + cluster-level) instead of hardcoding type aliases. Any type
whose base resolves to int8/int16/.../int64 is automatically recognized.

* fix: pass clusterName to all generators, remove dead code

- Pass clusterName to toCamelCase in generateStruct, generateCommand,
  generateEvent (fixes cluster-qualified FIELD_NAME_OVERRIDES not matching)
- Pass clusterName to toChipClassName in generateStruct, generateCommand,
  generateEvent, generateBitmap (fixes cluster-qualified CLASS_NAME_OVERRIDES)
- Pass "Globals" to generateEnum in generateGlobalsFile for consistency
- Remove identical if/else branches in resolvePythonType and attribute
  field generation

* chore: remove comparison scripts from tracked files

The compare_clusters.py and compare_summary.py scripts were developer
tools used during this work. Removed from git but kept locally.

* fix: add __all__ to Objects.py for mypy export resolution

mypy cannot resolve names re-exported via wildcard imports. Add a
complete __all__ listing all cluster names plus base classes and
primitive types so mypy sees them as explicit exports.

Fixes 11 mypy errors (name-defined, attr-defined) in node.py,
test_imports.py, and test_integration.py.

* fix: remove unreachable None check for deviceTypeList elements

deviceTypeList is typed as List[DeviceTypeStruct] (not Optional), so
elements are never None. mypy correctly flags the check as unreachable.

* chore: remove HeatingCoolingUnit extra device type

No longer needed — removed the hardcoded HeatingCoolingUnit (0x0300)
device type and the extra device types injection mechanism.

* fix: use correct field names IPv4Addresses/IPv6Addresses in client

The generated GeneralDiagnostics cluster uses IPv4Addresses/IPv6Addresses
(matching CHIP SDK), not iPv4Addresses/iPv6Addresses.

* fix: use correct attribute name LastNetworkID in client

The generated NetworkCommissioning cluster uses LastNetworkID (uppercase
ID from acronym expansion), not LastNetworkId.

* style: inline error messages in process_helpers.py

* style: apply ruff auto-fixes (FURB110, PLC0207)

- client.py: simplify `f.label if f.label else None` → `f.label or None`
- node.py: add maxsplit=1 to split() when only first element is used

* fix: generate commands for custom clusters with undefined direction

The @command decorator doesn't set direction on custom cluster commands,
causing them to be silently dropped by the generator's request/response
filter. Treat undefined direction as "request" and use effectiveAccess
for timed invoke check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add comment for `except NotImplementedError`

* fix: add `is_client` property to base class

* Update generated cluster_defs gitattributes

* Capitalize Heiman MutingSensor command

* Normalize generated Python command class names

* Restore camelCase Heiman command name

* Normalize generated Python event class names

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: TheJulianJES <TheJulianJES@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants