Skip to content

Commit a4c9ae8

Browse files
authored
fix: Generate definition when candidates present but no match found (#9046)
1 parent 3dad96a commit a4c9ae8

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

src/index.ts

+32-30
Original file line numberDiff line numberDiff line change
@@ -523,49 +523,51 @@ export async function findDefinition(device: Zh.Device, generateForUnknown = fal
523523
}
524524
}
525525

526-
if (!candidates) {
527-
if (!generateForUnknown || device.type === "Coordinator") {
528-
return undefined;
526+
if (candidates) {
527+
if (candidates.length === 1 && candidates[0].zigbeeModel) {
528+
return candidates[0];
529529
}
530530

531-
// Do not add this definition to cache, as device configuration might change.
532-
const {definition} = await generateDefinition(device);
531+
logger.debug(() => `Candidates for ${device.ieeeAddr}/${device.modelID}: ${candidates.map((c) => `${c.model}/${c.vendor}`)}`, NS);
533532

534-
return definition;
535-
}
536-
if (candidates.length === 1 && candidates[0].zigbeeModel) {
537-
return candidates[0];
538-
}
539-
logger.debug(() => `Candidates for ${device.ieeeAddr}/${device.modelID}: ${candidates.map((c) => `${c.model}/${c.vendor}`)}`, NS);
533+
// First try to match based on fingerprint, return the first matching one.
534+
const fingerprintMatch: {priority?: number; definition?: DefinitionWithExtend} = {priority: undefined, definition: undefined};
540535

541-
// First try to match based on fingerprint, return the first matching one.
542-
const fingerprintMatch: {priority?: number; definition?: DefinitionWithExtend} = {priority: undefined, definition: undefined};
536+
for (const candidate of candidates) {
537+
if (candidate.fingerprint) {
538+
for (const fingerprint of candidate.fingerprint) {
539+
const priority = fingerprint.priority ?? 0;
543540

544-
for (const candidate of candidates) {
545-
if (candidate.fingerprint) {
546-
for (const fingerprint of candidate.fingerprint) {
547-
const priority = fingerprint.priority ?? 0;
548-
549-
if (isFingerprintMatch(fingerprint, device) && (fingerprintMatch.priority === undefined || priority > fingerprintMatch.priority)) {
550-
fingerprintMatch.definition = candidate;
551-
fingerprintMatch.priority = priority;
541+
if (
542+
isFingerprintMatch(fingerprint, device) &&
543+
(fingerprintMatch.priority === undefined || priority > fingerprintMatch.priority)
544+
) {
545+
fingerprintMatch.definition = candidate;
546+
fingerprintMatch.priority = priority;
547+
}
552548
}
553549
}
554550
}
555-
}
556551

557-
if (fingerprintMatch.definition) {
558-
return fingerprintMatch.definition;
559-
}
552+
if (fingerprintMatch.definition) {
553+
return fingerprintMatch.definition;
554+
}
560555

561-
// Match based on fingerprint failed, return first matching definition based on zigbeeModel
562-
for (const candidate of candidates) {
563-
if (candidate.zigbeeModel && device.modelID && candidate.zigbeeModel.includes(device.modelID)) {
564-
return candidate;
556+
// Match based on fingerprint failed, return first matching definition based on zigbeeModel
557+
for (const candidate of candidates) {
558+
if (candidate.zigbeeModel && device.modelID && candidate.zigbeeModel.includes(device.modelID)) {
559+
return candidate;
560+
}
565561
}
566562
}
567563

568-
return undefined;
564+
if (!generateForUnknown || device.type === "Coordinator") {
565+
return undefined;
566+
}
567+
568+
const {definition} = await generateDefinition(device);
569+
570+
return definition;
569571
}
570572

571573
export async function generateExternalDefinitionSource(device: Zh.Device): Promise<string> {

test/index.test.ts

+35
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,41 @@ describe("ZHC", () => {
261261
expect(definition.model).toStrictEqual("BHT-002/BHT-006");
262262
});
263263

264+
it("finds definition by fingerprint - GP", async () => {
265+
const device = mockDevice(
266+
{
267+
modelID: "GreenPower_7",
268+
endpoints: [{ID: 242, profileID: undefined, deviceID: undefined, inputClusters: [], outputClusters: []}],
269+
},
270+
"GreenPower",
271+
{
272+
ieeeAddr: "0x0000000001511223",
273+
},
274+
);
275+
const definition = await findByDevice(device);
276+
277+
expect(definition.model).toStrictEqual("PTM 216Z");
278+
});
279+
280+
it("generates definition - GP - with no matching fingerprint from candidates", async () => {
281+
const device = mockDevice(
282+
{
283+
modelID: "GreenPower_2",
284+
endpoints: [{ID: 242, profileID: undefined, deviceID: undefined, inputClusters: [], outputClusters: []}],
285+
},
286+
"GreenPower",
287+
{
288+
ieeeAddr: "0x0000000052373160",
289+
},
290+
);
291+
292+
const definition = await findByDevice(device, true);
293+
expect(definition.model).toStrictEqual("GreenPower_2");
294+
expect(definition.vendor).toStrictEqual("");
295+
expect(definition.description).toStrictEqual("Automatically generated definition for Green Power");
296+
expect(definition.generated).toStrictEqual(true);
297+
});
298+
264299
it("allows definition with both modern extend and exposes as function", async () => {
265300
const device = mockDevice({modelID: "MOSZB-140", endpoints: []});
266301
const MOSZB140 = await findByDevice(device);

0 commit comments

Comments
 (0)