inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
142 lines (133 loc) • 3.77 kB
text/typescript
import { Powerlevel } from "@zwave-js/cc/safe";
import { getEnumMemberName } from "@zwave-js/shared/safe";
import { padStart } from "alcalzone-shared/strings";
import type {
LifelineHealthCheckResult,
LifelineHealthCheckSummary,
RouteHealthCheckResult,
RouteHealthCheckSummary,
} from "./_Types";
export const healthCheckTestFrameCount = 10;
export function healthCheckRatingToWord(rating: number): string {
return rating >= 10
? "perfect"
: rating >= 6
? "good"
: rating >= 4
? "acceptable"
: rating >= 1
? "bad"
: "dead";
}
export function formatLifelineHealthCheckRound(
round: number,
numRounds: number,
result: LifelineHealthCheckResult,
): string {
const ret = [
`· round ${padStart(
round.toString(),
Math.floor(Math.log10(numRounds) + 1),
" ",
)} - rating: ${result.rating} (${healthCheckRatingToWord(
result.rating,
)})`,
` failed pings → node: ${result.failedPingsNode}/${healthCheckTestFrameCount}`,
` max. latency: ${result.latency.toFixed(1)} ms`,
result.routeChanges != undefined
? ` route changes: ${result.routeChanges}`
: "",
result.snrMargin != undefined
? ` SNR margin: ${result.snrMargin} dBm`
: "",
result.failedPingsController != undefined
? ` failed pings → controller: ${result.failedPingsController}/${healthCheckTestFrameCount} at normal power`
: result.minPowerlevel != undefined
? ` min. node powerlevel w/o errors: ${getEnumMemberName(
Powerlevel,
result.minPowerlevel,
)}`
: "",
]
.filter((line) => !!line)
.join("\n");
return ret;
}
export function formatLifelineHealthCheckSummary(
summary: LifelineHealthCheckSummary,
): string {
return `
rating: ${summary.rating} (${healthCheckRatingToWord(
summary.rating,
)})
no. of routing neighbors: ${
summary.results[summary.results.length - 1].numNeighbors
}
Check rounds:
${summary.results
.map((r, i) =>
formatLifelineHealthCheckRound(i + 1, summary.results.length, r),
)
.join("\n \n")}`.trim();
}
export function formatRouteHealthCheckRound(
sourceNodeId: number,
targetNodeId: number,
round: number,
numRounds: number,
result: RouteHealthCheckResult,
): string {
const ret = [
`· round ${padStart(
round.toString(),
Math.floor(Math.log10(numRounds) + 1),
" ",
)} - rating: ${result.rating} (${healthCheckRatingToWord(
result.rating,
)})`,
result.failedPingsToTarget != undefined
? ` failed pings ${sourceNodeId} → ${targetNodeId}: ${result.failedPingsToTarget}/${healthCheckTestFrameCount}`
: result.minPowerlevelSource != undefined
? ` Node ${sourceNodeId} min. powerlevel w/o errors: ${getEnumMemberName(
Powerlevel,
result.minPowerlevelSource,
)}`
: "",
result.failedPingsToSource != undefined
? ` failed pings ${targetNodeId} → ${sourceNodeId}: ${result.failedPingsToSource}/${healthCheckTestFrameCount}`
: result.minPowerlevelTarget != undefined
? ` Node ${targetNodeId} min. powerlevel w/o errors: ${getEnumMemberName(
Powerlevel,
result.minPowerlevelTarget,
)}`
: "",
]
.filter((line) => !!line)
.join("\n");
return ret;
}
export function formatRouteHealthCheckSummary(
sourceNodeId: number,
targetNodeId: number,
summary: RouteHealthCheckSummary,
): string {
return `
rating: ${summary.rating} (${healthCheckRatingToWord(
summary.rating,
)})
no. of routing neighbors: ${
summary.results[summary.results.length - 1].numNeighbors
}
Check rounds:
${summary.results
.map((r, i) =>
formatRouteHealthCheckRound(
sourceNodeId,
targetNodeId,
i + 1,
summary.results.length,
r,
),
)
.join("\n \n")}`.trim();
}