inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
101 lines (94 loc) • 3.18 kB
text/typescript
import * as Sentry from "@sentry/node";
import { AssociationGroupInfoCC, ConfigurationCC } from "@zwave-js/cc";
import { CommandClasses } from "@zwave-js/core";
import type { ZWaveApplicationHost } from "@zwave-js/host";
import { formatId } from "@zwave-js/shared";
import { isObject } from "alcalzone-shared/typeguards";
import axios from "axios";
import type { ZWaveNode } from "../node/Node";
const missingDeviceConfigCache = new Set<string>();
export async function reportMissingDeviceConfig(
applHost: ZWaveApplicationHost,
node: ZWaveNode & {
manufacturerId: number;
productType: number;
productId: number;
firmwareVersion: string;
},
): Promise<void> {
const configFingerprint = `${formatId(node.manufacturerId)}:${formatId(
node.productType,
)}:${formatId(node.productId)}:${node.firmwareVersion}`;
// We used to get a LOT of false positives, so we should check with our device
// database whether this config file is actually unknown
// If we tried to report this file earlier, we can skip the report
if (missingDeviceConfigCache.has(configFingerprint)) return;
// Otherwise ask our device DB if it exists
try {
const { data } = await axios.get(
`https://devices.zwave-js.io/public_api/getdeviceinfo/${configFingerprint.replace(
/:/g,
"/",
)}`,
);
if (
isObject(data) &&
typeof data.deviceFound === "boolean" &&
data.deviceFound
) {
// This is a false positive - remember it
missingDeviceConfigCache.add(configFingerprint);
return;
}
} catch (e) {
// didn't work, try again next time
return;
}
const message = `Missing device config: ${configFingerprint}`;
const deviceInfo: Record<string, any> = {
supportsConfigCCV3:
node.getCCVersion(CommandClasses.Configuration) >= 3,
supportsAGI: node.supportsCC(
CommandClasses["Association Group Information"],
),
supportsZWavePlus: node.supportsCC(CommandClasses["Z-Wave Plus Info"]),
};
try {
if (deviceInfo.supportsConfigCCV3) {
// Try to collect all info about config params we can get
const instance = node.createCCInstanceUnsafe(ConfigurationCC)!;
deviceInfo.parameters = instance.getQueriedParamInfos(applHost);
}
if (deviceInfo.supportsAGI) {
// Try to collect all info about association groups we can get
const associationGroupCount = AssociationGroupInfoCC[
"getAssociationGroupCountCached"
](applHost, node);
const names: string[] = [];
for (let group = 1; group <= associationGroupCount; group++) {
names.push(
AssociationGroupInfoCC.getGroupNameCached(
applHost,
node,
group,
) ?? "",
);
}
deviceInfo.associationGroups = names;
}
if (deviceInfo.supportsZWavePlus) {
deviceInfo.zWavePlusVersion = node.zwavePlusVersion;
}
} catch {
// Don't fail on the last meters :)
}
Sentry.captureMessage(message, (scope) => {
scope.clearBreadcrumbs();
// Group by device config, otherwise Sentry groups by "Unknown device config", which is nonsense
scope.setFingerprint([configFingerprint]);
scope.setExtras(deviceInfo);
return scope;
});
// Remember that we reported the config
missingDeviceConfigCache.add(configFingerprint);
}