Expose bools as metrics as well
This commit is contained in:
parent
f1b48575cb
commit
78a8972bb0
4 changed files with 51 additions and 22 deletions
|
@ -1,20 +1,27 @@
|
|||
import { Array, Intersect, Literal, Number, Optional, Record, Static, String, Union } from 'runtypes'
|
||||
|
||||
export const NUMBER_TYPES = ['float', 'int', 'uint8', 'uint16', 'uint32', 'uint64'] as const
|
||||
const NumberTypesLiterals = NUMBER_TYPES.map(Literal)
|
||||
const NumberTypesBoundary = Union(NumberTypesLiterals[0], ...NumberTypesLiterals)
|
||||
export type NumberTypes = Static<typeof NumberTypesBoundary>
|
||||
export const NUMBER_TYPES = [] as const
|
||||
|
||||
const NumberAlikeTypesTypesBoundary = Union(
|
||||
Literal('bool'),
|
||||
Literal('float'),
|
||||
Literal('int'),
|
||||
Literal('uint8'),
|
||||
Literal('uint16'),
|
||||
Literal('uint32'),
|
||||
Literal('uint64'),
|
||||
)
|
||||
export type NumberAlikeTypes = Static<typeof NumberAlikeTypesTypesBoundary>
|
||||
|
||||
export const CharacteristicBoundary = Intersect(
|
||||
Record({ type: String, description: String }),
|
||||
Union(
|
||||
Record({
|
||||
format: NumberTypesBoundary,
|
||||
format: NumberAlikeTypesTypesBoundary,
|
||||
value: Optional(Number),
|
||||
unit: Optional(String),
|
||||
}),
|
||||
Record({ format: Literal('string'), value: String }),
|
||||
Record({ format: Literal('bool') }),
|
||||
),
|
||||
)
|
||||
export type Characteristic = Static<typeof CharacteristicBoundary>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { Accessory, Device, Service } from './boundaries'
|
||||
import { isType } from './std'
|
||||
import { NUMBER_TYPES } from './boundaries'
|
||||
import { assertTypeExhausted, isType } from './std'
|
||||
import { Service as HapService } from 'hap-nodejs'
|
||||
|
||||
export class Metric {
|
||||
|
@ -29,20 +28,33 @@ export function aggregate(devices: Device[], timestamp: Date): Metric[] {
|
|||
...getServiceLabels(service),
|
||||
}
|
||||
for (const characteristic of service.characteristics) {
|
||||
for (const numberType of NUMBER_TYPES) {
|
||||
if (characteristic.format === numberType && typeof characteristic.value !== 'undefined') {
|
||||
if (METRICS_FILTER.includes(characteristic.description)) {
|
||||
continue
|
||||
}
|
||||
const name = formatName(
|
||||
uuidToServerName(service.type),
|
||||
characteristic.description,
|
||||
characteristic.unit,
|
||||
)
|
||||
if (!METRICS_FILTER.includes(name)) {
|
||||
const format = characteristic.format
|
||||
switch (format) {
|
||||
case 'string':
|
||||
break
|
||||
|
||||
case 'bool':
|
||||
case 'float':
|
||||
case 'int':
|
||||
case 'uint8':
|
||||
case 'uint16':
|
||||
case 'uint32':
|
||||
case 'uint64':
|
||||
if (typeof characteristic.value !== 'undefined') {
|
||||
if (METRICS_FILTER.includes(characteristic.description)) {
|
||||
break
|
||||
}
|
||||
const name = formatName(
|
||||
uuidToServerName(service.type),
|
||||
characteristic.description,
|
||||
characteristic.unit,
|
||||
)
|
||||
metrics.push(new Metric(name, characteristic.value, timestamp, labels))
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
assertTypeExhausted(format)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,10 +129,10 @@ function uuidToServerName(uuid: string): string {
|
|||
for (const name of Object.getOwnPropertyNames(HapService)) {
|
||||
const maybeService = (HapService as unknown as Record<string, unknown>)[name]
|
||||
if (typeof maybeService === 'function' && 'UUID' in maybeService) {
|
||||
if ((maybeService as Record<string,string>)['UUID'] === uuid) {
|
||||
if ((maybeService as Record<string, string>)['UUID'] === uuid) {
|
||||
return name
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not resolve UUID ${uuid} to service`)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,3 +9,7 @@ interface TypeMap {
|
|||
export function isType<T extends Types>(type: T): (v: unknown) => v is TypeMap[T] {
|
||||
return (v: unknown): v is TypeMap[T] => typeof v === type
|
||||
}
|
||||
|
||||
export function assertTypeExhausted(v: never): never {
|
||||
throw new Error(`Type should be exhausted but is not. Value "${JSON.stringify(v)}`)
|
||||
}
|
||||
|
|
|
@ -69,11 +69,16 @@ describe('Metrics aggregator', () => {
|
|||
}
|
||||
|
||||
expect(aggregate([tpLink], timestamp)).toEqual([
|
||||
new Metric('outlet_on', 0, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_in_use', 0, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_amperes_a', 0.03, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_total_consumption_kwh', 0.051, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_apparent_power_va', 53248.8, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_volts_v', 230.8, timestamp, expectedLabelsAccessory1),
|
||||
new Metric('outlet_consumption_w', 0, timestamp, expectedLabelsAccessory1),
|
||||
|
||||
new Metric('outlet_on', 0, timestamp, expectedLabelsAccessory2),
|
||||
new Metric('outlet_in_use', 0, timestamp, expectedLabelsAccessory2),
|
||||
new Metric('outlet_amperes_a', 0.03, timestamp, expectedLabelsAccessory2),
|
||||
new Metric('outlet_total_consumption_kwh', 13.025, timestamp, expectedLabelsAccessory2),
|
||||
new Metric('outlet_apparent_power_va', 53365.6, timestamp, expectedLabelsAccessory2),
|
||||
|
@ -145,6 +150,7 @@ describe('Metrics aggregator', () => {
|
|||
|
||||
new Metric('speaker_active', 1, timestamp, expectedLabels4),
|
||||
new Metric('speaker_volume_control_type', 3, timestamp, expectedLabels4),
|
||||
new Metric('speaker_mute', 0, timestamp, expectedLabels4),
|
||||
new Metric('speaker_volume_percentage', 50, timestamp, expectedLabels4),
|
||||
])
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue