Initial version
This commit is contained in:
parent
dd4a135022
commit
00dd20559a
35 changed files with 16250 additions and 6737 deletions
38
.eslintrc
38
.eslintrc
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended" // uses the recommended rules from the @typescript-eslint/eslint-plugin
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"dist"
|
||||
],
|
||||
"rules": {
|
||||
"quotes": ["warn", "single"],
|
||||
"indent": ["warn", 2, { "SwitchCase": 1 }],
|
||||
"semi": ["off"],
|
||||
"comma-dangle": ["warn", "always-multiline"],
|
||||
"dot-notation": "off",
|
||||
"eqeqeq": "warn",
|
||||
"curly": ["warn", "all"],
|
||||
"brace-style": ["warn"],
|
||||
"prefer-arrow-callback": ["warn"],
|
||||
"max-len": ["warn", 140],
|
||||
"no-console": ["warn"], // use the provided Homebridge log method instead
|
||||
"no-non-null-assertion": ["off"],
|
||||
"comma-spacing": ["error"],
|
||||
"no-multi-spaces": ["warn", { "ignoreEOLComments": true }],
|
||||
"no-trailing-spaces": ["warn"],
|
||||
"lines-between-class-members": ["warn", "always", {"exceptAfterSingleLine": true}],
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/semi": ["warn"],
|
||||
"@typescript-eslint/member-delimiter-style": ["warn"]
|
||||
}
|
||||
}
|
23
.eslintrc.js
Normal file
23
.eslintrc.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
module.exports = {
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint', 'prettier'],
|
||||
root: true,
|
||||
rules: {
|
||||
'prettier/prettier': 'warn',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'error',
|
||||
'prefer-arrow-callback': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['.eslintrc.js', 'jest.config.js', 'prettier.config.js'],
|
||||
env: {
|
||||
node: true,
|
||||
browser: false,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -111,10 +111,17 @@ dist
|
|||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
/.vscode/
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.pnp.*
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ
|
||||
/.idea/
|
||||
|
||||
/dot-homebridge/accessories/
|
||||
/dot-homebridge/persist/
|
||||
|
|
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"files.eol": "\n",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"editor.rulers": [ 140 ],
|
||||
"eslint.enable": true
|
||||
}
|
2
TODOs
Normal file
2
TODOs
Normal file
|
@ -0,0 +1,2 @@
|
|||
- Extract PrometheusFormatter
|
||||
- Extract HttpServer
|
|
@ -1,16 +1,50 @@
|
|||
{
|
||||
"pluginAlias": "ExampleHomebridgePlugin",
|
||||
"pluginType": "platform",
|
||||
"singular": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Name",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"default": "Example Dynamic Platform"
|
||||
}
|
||||
"pluginAlias": "PrometheusExporter",
|
||||
"pluginType": "platform",
|
||||
"singular": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pin": {
|
||||
"title": "Pin",
|
||||
"description": "Homebridge PIN for service authentication",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"debug": {
|
||||
"title": "Debug",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": false
|
||||
},
|
||||
"probe_port": {
|
||||
"title": "Probe server port",
|
||||
"description": "TCP port for the prometheus probe server to listen to",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"default": 36123
|
||||
},
|
||||
"refresh_interval": {
|
||||
"title": "Service refresh interval",
|
||||
"description": "Discover new services every <interval> seconds",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"default": 60
|
||||
},
|
||||
"request_timeout": {
|
||||
"title": "Request timeout",
|
||||
"description": "Request timeout when interacting with homebridge instances",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"default": 10
|
||||
},
|
||||
"discovery_timeout": {
|
||||
"title": "Service discovery timeout",
|
||||
"description": "Discovery timeout after which the current discovery is considered failed",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"default": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
dot-homebridge/config.json
Normal file
25
dot-homebridge/config.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"accessories": [],
|
||||
"bridge": {
|
||||
"name": "Prometheus Exporter Test Homebridge",
|
||||
"pin": "121-11-121"
|
||||
},
|
||||
"platforms": [
|
||||
{
|
||||
"pin": "808-00-808",
|
||||
"platform": "PrometheusExporter",
|
||||
"debug": true
|
||||
},
|
||||
{
|
||||
"platform": "cmdSwitch2",
|
||||
"switches": [
|
||||
{
|
||||
"name": "Test",
|
||||
"on_cmd": "echo on",
|
||||
"off_cmd": "echo off",
|
||||
"state_cmd": "test $(echo \"`date +\"%s\"` % 4\" | bc) -eq 0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
43
flake.lock
Normal file
43
flake.lock
Normal file
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1667629849,
|
||||
"narHash": "sha256-P+v+nDOFWicM4wziFK9S/ajF2lc0N2Rg9p6Y35uMoZI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3bacde6273b09a21a8ccfba15586fb165078fb62",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
21
flake.nix
Normal file
21
flake.nix
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
description = "Ansible environment";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
config = { allowUnfree = true; };
|
||||
system = system;
|
||||
};
|
||||
|
||||
in with pkgs; rec {
|
||||
|
||||
devShell = pkgs.mkShell rec { buildInputs = with pkgs; [ nodejs ]; };
|
||||
});
|
||||
}
|
6
jest.config.js
Normal file
6
jest.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
verbose: true,
|
||||
}
|
20
nodemon.json
20
nodemon.json
|
@ -1,12 +1,10 @@
|
|||
{
|
||||
"watch": [
|
||||
"src"
|
||||
],
|
||||
"ext": "ts",
|
||||
"ignore": [],
|
||||
"exec": "tsc && homebridge -I -D",
|
||||
"signal": "SIGTERM",
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--trace-warnings"
|
||||
}
|
||||
}
|
||||
"watch": ["src"],
|
||||
"ext": "ts",
|
||||
"ignore": [],
|
||||
"exec": "tsc && homebridge -D -U dot-homebridge",
|
||||
"signal": "SIGTERM",
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--trace-warnings"
|
||||
}
|
||||
}
|
||||
|
|
19729
package-lock.json
generated
19729
package-lock.json
generated
File diff suppressed because it is too large
Load diff
89
package.json
89
package.json
|
@ -1,41 +1,52 @@
|
|||
{
|
||||
"private": true,
|
||||
"displayName": "Plugin Name",
|
||||
"name": "homebridge-plugin-name",
|
||||
"version": "1.0.0",
|
||||
"description": "A short description about what your plugin does.",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/USERNAME/GITHUB_PROJECT_NAME.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/USERNAME/GITHUB_PROJECT_NAME/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.1",
|
||||
"homebridge": ">=1.3.5"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint src/**.ts --max-warnings=0",
|
||||
"watch": "npm run build && npm link && nodemon",
|
||||
"build": "rimraf ./dist && tsc",
|
||||
"prepublishOnly": "npm run lint && npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"homebridge-plugin"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.10.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.1",
|
||||
"homebridge": "^1.3.5",
|
||||
"nodemon": "^2.0.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.3.0",
|
||||
"typescript": "^4.4.4"
|
||||
}
|
||||
"private": true,
|
||||
"name": "homebridge-prometheus-exporter",
|
||||
"version": "1.0.0",
|
||||
"description": "Prometheus exporter for homebridge accessories.",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lstrojny/homebridge-prometheus-exporter.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/lstrojny/homebridge-prometheus-exporter/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.1",
|
||||
"homebridge": ">=1.3.5"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"lint": "npm run format && eslint --ignore-path=.gitignore '**/**.{ts,js,json}'",
|
||||
"watch": "npm run build && npm run link && nodemon",
|
||||
"watch-tests": "jest --watch",
|
||||
"tests": "jest",
|
||||
"link": "npm install --no-save file:///$PWD/",
|
||||
"build": "rimraf ./dist && tsc",
|
||||
"format": "prettier --ignore-path=.gitignore --write '**/**.{ts,js,json}'",
|
||||
"prepublishOnly": "npm run lint && npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"homebridge-plugin"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.10.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"homebridge": "^1.3.5",
|
||||
"homebridge-cmdswitch2": "^0.2.10",
|
||||
"nodemon": "^2.0.13",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-node": "^10.3.0",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify": "^4.9.2",
|
||||
"hap-node-client": "git+https://github.com/NorthernMan54/Hap-Node-Client.git#fe200ba",
|
||||
"runtypes": "^6.6.0"
|
||||
}
|
||||
}
|
||||
|
|
9
prettier.config.js
Normal file
9
prettier.config.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
tabWidth: 4,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
printWidth: 120,
|
||||
trailingComma: 'all',
|
||||
quoteProps: 'as-needed',
|
||||
proseWrap: 'always',
|
||||
}
|
1
src/ambient.d.ts
vendored
Normal file
1
src/ambient.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
declare module 'hap-node-client'
|
46
src/boundaries.ts
Normal file
46
src/boundaries.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { Number, String, Literal, Array, Record, Union, Static, Optional, Intersect } 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 CharacteristicBoundary = Intersect(
|
||||
Record({ type: String, description: String }),
|
||||
Union(
|
||||
Record({
|
||||
format: NumberTypesBoundary,
|
||||
value: Optional(Number),
|
||||
unit: Optional(String),
|
||||
}),
|
||||
Record({ format: Literal('string'), value: String }),
|
||||
Record({ format: Literal('bool') }),
|
||||
),
|
||||
)
|
||||
export type Characteristic = Static<typeof CharacteristicBoundary>
|
||||
|
||||
export const ServiceBoundary = Record({
|
||||
type: String,
|
||||
characteristics: Array(CharacteristicBoundary),
|
||||
})
|
||||
export type Service = Static<typeof ServiceBoundary>
|
||||
|
||||
export const AccessoryBoundary = Record({
|
||||
services: Array(ServiceBoundary),
|
||||
})
|
||||
export type Accessory = Static<typeof AccessoryBoundary>
|
||||
|
||||
export const InstanceBoundary = Record({
|
||||
deviceID: String,
|
||||
name: String,
|
||||
url: String,
|
||||
})
|
||||
export type Instance = Static<typeof InstanceBoundary>
|
||||
|
||||
export const DeviceBoundary = Record({
|
||||
instance: InstanceBoundary,
|
||||
accessories: Record({
|
||||
accessories: Array(AccessoryBoundary),
|
||||
}),
|
||||
})
|
||||
export type Device = Static<typeof DeviceBoundary>
|
14
src/discovery/api.ts
Normal file
14
src/discovery/api.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import type { Device } from '../boundaries'
|
||||
import { Logger } from 'homebridge'
|
||||
|
||||
type Pin = string
|
||||
|
||||
export type HapConfig = {
|
||||
pin: Pin
|
||||
refreshInterval: number
|
||||
discoveryTimeout: number
|
||||
requestTimeout: number
|
||||
logger: Logger
|
||||
debug: boolean
|
||||
}
|
||||
export type HapDiscover = (config: HapConfig) => Promise<Device[]>
|
45
src/discovery/hap_node_js_client.ts
Normal file
45
src/discovery/hap_node_js_client.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import type { HapDiscover } from './api'
|
||||
import { HAPNodeJSClient } from 'hap-node-client'
|
||||
|
||||
import { Device, DeviceBoundary } from '../boundaries'
|
||||
import { Array, Unknown } from 'runtypes'
|
||||
|
||||
const MaybeDevices = Array(Unknown)
|
||||
|
||||
export const discover: HapDiscover = ({ pin, refreshInterval, discoveryTimeout, requestTimeout, logger, debug }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const client = new HAPNodeJSClient({
|
||||
debug: debug,
|
||||
refresh: refreshInterval,
|
||||
timeout: discoveryTimeout,
|
||||
reqTimeout: requestTimeout,
|
||||
pin,
|
||||
})
|
||||
|
||||
client.on('Ready', (deviceData: unknown) => {
|
||||
try {
|
||||
const devices: Device[] = []
|
||||
|
||||
for (const device of MaybeDevices.check(deviceData)) {
|
||||
try {
|
||||
devices.push(DeviceBoundary.check(device))
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Boundary check for device data failed %o %s',
|
||||
e,
|
||||
JSON.stringify(device, null, 4),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resolve(devices)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
}
|
700
src/hap.ts
Normal file
700
src/hap.ts
Normal file
|
@ -0,0 +1,700 @@
|
|||
/** Copied from https://github.com/oznu/hap-client/blob/master/src/hap-types.ts */
|
||||
|
||||
export const Services = {
|
||||
'00000260-0000-1000-8000-0026BB765291': 'AccessCode',
|
||||
AccessCode: '00000260-0000-1000-8000-0026BB765291',
|
||||
'000000DA-0000-1000-8000-0026BB765291': 'AccessControl',
|
||||
AccessControl: '000000DA-0000-1000-8000-0026BB765291',
|
||||
'0000003E-0000-1000-8000-0026BB765291': 'AccessoryInformation',
|
||||
AccessoryInformation: '0000003E-0000-1000-8000-0026BB765291',
|
||||
'00000270-0000-1000-8000-0026BB765291': 'AccessoryMetrics',
|
||||
AccessoryMetrics: '00000270-0000-1000-8000-0026BB765291',
|
||||
'00000239-0000-1000-8000-0026BB765291': 'AccessoryRuntimeInformation',
|
||||
AccessoryRuntimeInformation: '00000239-0000-1000-8000-0026BB765291',
|
||||
'000000BB-0000-1000-8000-0026BB765291': 'AirPurifier',
|
||||
AirPurifier: '000000BB-0000-1000-8000-0026BB765291',
|
||||
'0000008D-0000-1000-8000-0026BB765291': 'AirQualitySensor',
|
||||
AirQualitySensor: '0000008D-0000-1000-8000-0026BB765291',
|
||||
'00000267-0000-1000-8000-0026BB765291': 'AssetUpdate',
|
||||
AssetUpdate: '00000267-0000-1000-8000-0026BB765291',
|
||||
'0000026A-0000-1000-8000-0026BB765291': 'Assistant',
|
||||
Assistant: '0000026A-0000-1000-8000-0026BB765291',
|
||||
'00000127-0000-1000-8000-0026BB765291': 'AudioStreamManagement',
|
||||
AudioStreamManagement: '00000127-0000-1000-8000-0026BB765291',
|
||||
'00000096-0000-1000-8000-0026BB765291': 'BatteryService',
|
||||
BatteryService: '00000096-0000-1000-8000-0026BB765291',
|
||||
Battery: '00000096-0000-1000-8000-0026BB765291',
|
||||
'000000A1-0000-1000-8000-0026BB765291': 'BridgeConfiguration',
|
||||
BridgeConfiguration: '000000A1-0000-1000-8000-0026BB765291',
|
||||
'00000062-0000-1000-8000-0026BB765291': 'BridgingState',
|
||||
BridgingState: '00000062-0000-1000-8000-0026BB765291',
|
||||
'00000111-0000-1000-8000-0026BB765291': 'CameraControl',
|
||||
CameraControl: '00000111-0000-1000-8000-0026BB765291',
|
||||
'0000021A-0000-1000-8000-0026BB765291': 'CameraOperatingMode',
|
||||
CameraOperatingMode: '0000021A-0000-1000-8000-0026BB765291',
|
||||
'00000204-0000-1000-8000-0026BB765291': 'CameraEventRecordingManagement',
|
||||
CameraEventRecordingManagement: '00000204-0000-1000-8000-0026BB765291',
|
||||
CameraRecordingManagement: '00000204-0000-1000-8000-0026BB765291',
|
||||
'00000110-0000-1000-8000-0026BB765291': 'CameraRTPStreamManagement',
|
||||
CameraRTPStreamManagement: '00000110-0000-1000-8000-0026BB765291',
|
||||
'00000097-0000-1000-8000-0026BB765291': 'CarbonDioxideSensor',
|
||||
CarbonDioxideSensor: '00000097-0000-1000-8000-0026BB765291',
|
||||
'0000007F-0000-1000-8000-0026BB765291': 'CarbonMonoxideSensor',
|
||||
CarbonMonoxideSensor: '0000007F-0000-1000-8000-0026BB765291',
|
||||
'0000005A-0000-1000-8000-0026BB765291': 'Relay',
|
||||
Relay: '0000005A-0000-1000-8000-0026BB765291',
|
||||
CloudRelay: '0000005A-0000-1000-8000-0026BB765291',
|
||||
'00000080-0000-1000-8000-0026BB765291': 'ContactSensor',
|
||||
ContactSensor: '00000080-0000-1000-8000-0026BB765291',
|
||||
'00000129-0000-1000-8000-0026BB765291': 'DataStreamTransportManagement',
|
||||
DataStreamTransportManagement: '00000129-0000-1000-8000-0026BB765291',
|
||||
'00000237-0000-1000-8000-0026BB765291': 'Diagnostics',
|
||||
Diagnostics: '00000237-0000-1000-8000-0026BB765291',
|
||||
'00000081-0000-1000-8000-0026BB765291': 'Door',
|
||||
Door: '00000081-0000-1000-8000-0026BB765291',
|
||||
'00000121-0000-1000-8000-0026BB765291': 'Doorbell',
|
||||
Doorbell: '00000121-0000-1000-8000-0026BB765291',
|
||||
'00000040-0000-1000-8000-0026BB765291': 'Fan',
|
||||
Fan: '00000040-0000-1000-8000-0026BB765291',
|
||||
'000000B7-0000-1000-8000-0026BB765291': 'Fanv2',
|
||||
Fanv2: '000000B7-0000-1000-8000-0026BB765291',
|
||||
'000000D7-0000-1000-8000-0026BB765291': 'Faucet',
|
||||
Faucet: '000000D7-0000-1000-8000-0026BB765291',
|
||||
'000000BA-0000-1000-8000-0026BB765291': 'FilterMaintenance',
|
||||
FilterMaintenance: '000000BA-0000-1000-8000-0026BB765291',
|
||||
'00000041-0000-1000-8000-0026BB765291': 'GarageDoorOpener',
|
||||
GarageDoorOpener: '00000041-0000-1000-8000-0026BB765291',
|
||||
'000000BC-0000-1000-8000-0026BB765291': 'HeaterCooler',
|
||||
HeaterCooler: '000000BC-0000-1000-8000-0026BB765291',
|
||||
'000000BD-0000-1000-8000-0026BB765291': 'HumidifierDehumidifier',
|
||||
HumidifierDehumidifier: '000000BD-0000-1000-8000-0026BB765291',
|
||||
'00000082-0000-1000-8000-0026BB765291': 'HumiditySensor',
|
||||
HumiditySensor: '00000082-0000-1000-8000-0026BB765291',
|
||||
'000000D9-0000-1000-8000-0026BB765291': 'InputSource',
|
||||
InputSource: '000000D9-0000-1000-8000-0026BB765291',
|
||||
'000000CF-0000-1000-8000-0026BB765291': 'IrrigationSystem',
|
||||
IrrigationSystem: '000000CF-0000-1000-8000-0026BB765291',
|
||||
'00000083-0000-1000-8000-0026BB765291': 'LeakSensor',
|
||||
LeakSensor: '00000083-0000-1000-8000-0026BB765291',
|
||||
'00000043-0000-1000-8000-0026BB765291': 'Lightbulb',
|
||||
Lightbulb: '00000043-0000-1000-8000-0026BB765291',
|
||||
'00000084-0000-1000-8000-0026BB765291': 'LightSensor',
|
||||
LightSensor: '00000084-0000-1000-8000-0026BB765291',
|
||||
'00000044-0000-1000-8000-0026BB765291': 'LockManagement',
|
||||
LockManagement: '00000044-0000-1000-8000-0026BB765291',
|
||||
'00000045-0000-1000-8000-0026BB765291': 'LockMechanism',
|
||||
LockMechanism: '00000045-0000-1000-8000-0026BB765291',
|
||||
'00000112-0000-1000-8000-0026BB765291': 'Microphone',
|
||||
Microphone: '00000112-0000-1000-8000-0026BB765291',
|
||||
'00000085-0000-1000-8000-0026BB765291': 'MotionSensor',
|
||||
MotionSensor: '00000085-0000-1000-8000-0026BB765291',
|
||||
'00000266-0000-1000-8000-0026BB765291': 'NFCAccess',
|
||||
NFCAccess: '00000266-0000-1000-8000-0026BB765291',
|
||||
'00000086-0000-1000-8000-0026BB765291': 'OccupancySensor',
|
||||
OccupancySensor: '00000086-0000-1000-8000-0026BB765291',
|
||||
'00000047-0000-1000-8000-0026BB765291': 'Outlet',
|
||||
Outlet: '00000047-0000-1000-8000-0026BB765291',
|
||||
'00000055-0000-1000-8000-0026BB765291': 'Pairing',
|
||||
Pairing: '00000055-0000-1000-8000-0026BB765291',
|
||||
'00000221-0000-1000-8000-0026BB765291': 'PowerManagement',
|
||||
PowerManagement: '00000221-0000-1000-8000-0026BB765291',
|
||||
'000000A2-0000-1000-8000-0026BB765291': 'ProtocolInformation',
|
||||
ProtocolInformation: '000000A2-0000-1000-8000-0026BB765291',
|
||||
'0000007E-0000-1000-8000-0026BB765291': 'SecuritySystem',
|
||||
SecuritySystem: '0000007E-0000-1000-8000-0026BB765291',
|
||||
'000000CC-0000-1000-8000-0026BB765291': 'ServiceLabel',
|
||||
ServiceLabel: '000000CC-0000-1000-8000-0026BB765291',
|
||||
'00000133-0000-1000-8000-0026BB765291': 'Siri',
|
||||
Siri: '00000133-0000-1000-8000-0026BB765291',
|
||||
'00000253-0000-1000-8000-0026BB765291': 'SiriEndpoint',
|
||||
SiriEndpoint: '00000253-0000-1000-8000-0026BB765291',
|
||||
'000000B9-0000-1000-8000-0026BB765291': 'Slat',
|
||||
Slat: '000000B9-0000-1000-8000-0026BB765291',
|
||||
Slats: '000000B9-0000-1000-8000-0026BB765291',
|
||||
'00000228-0000-1000-8000-0026BB765291': 'SmartSpeaker',
|
||||
SmartSpeaker: '00000228-0000-1000-8000-0026BB765291',
|
||||
'00000087-0000-1000-8000-0026BB765291': 'SmokeSensor',
|
||||
SmokeSensor: '00000087-0000-1000-8000-0026BB765291',
|
||||
'00000113-0000-1000-8000-0026BB765291': 'Speaker',
|
||||
Speaker: '00000113-0000-1000-8000-0026BB765291',
|
||||
'00000088-0000-1000-8000-0026BB765291': 'StatefulProgrammableSwitch',
|
||||
StatefulProgrammableSwitch: '00000088-0000-1000-8000-0026BB765291',
|
||||
'00000089-0000-1000-8000-0026BB765291': 'StatelessProgrammableSwitch',
|
||||
StatelessProgrammableSwitch: '00000089-0000-1000-8000-0026BB765291',
|
||||
'00000049-0000-1000-8000-0026BB765291': 'Switch',
|
||||
Switch: '00000049-0000-1000-8000-0026BB765291',
|
||||
'00000125-0000-1000-8000-0026BB765291': 'TargetControl',
|
||||
TargetControl: '00000125-0000-1000-8000-0026BB765291',
|
||||
'00000122-0000-1000-8000-0026BB765291': 'TargetControlManagement',
|
||||
TargetControlManagement: '00000122-0000-1000-8000-0026BB765291',
|
||||
'000000D8-0000-1000-8000-0026BB765291': 'Television',
|
||||
Television: '000000D8-0000-1000-8000-0026BB765291',
|
||||
TelevisionSpeaker: '00000113-0000-1000-8000-0026BB765291',
|
||||
'0000008A-0000-1000-8000-0026BB765291': 'TemperatureSensor',
|
||||
TemperatureSensor: '0000008A-0000-1000-8000-0026BB765291',
|
||||
'0000004A-0000-1000-8000-0026BB765291': 'Thermostat',
|
||||
Thermostat: '0000004A-0000-1000-8000-0026BB765291',
|
||||
'00000701-0000-1000-8000-0026BB765291': 'ThreadTransport',
|
||||
ThreadTransport: '00000701-0000-1000-8000-0026BB765291',
|
||||
'00000099-0000-1000-8000-0026BB765291': 'TimeInformation',
|
||||
TimeInformation: '00000099-0000-1000-8000-0026BB765291',
|
||||
'00000203-0000-1000-8000-0026BB765291': 'TransferTransportManagement',
|
||||
TransferTransportManagement: '00000203-0000-1000-8000-0026BB765291',
|
||||
'00000056-0000-1000-8000-0026BB765291': 'TunneledBTLEAccessoryService',
|
||||
TunneledBTLEAccessoryService: '00000056-0000-1000-8000-0026BB765291',
|
||||
Tunnel: '00000056-0000-1000-8000-0026BB765291',
|
||||
'000000D0-0000-1000-8000-0026BB765291': 'Valve',
|
||||
Valve: '000000D0-0000-1000-8000-0026BB765291',
|
||||
'0000020A-0000-1000-8000-0026BB765291': 'WiFiRouter',
|
||||
WiFiRouter: '0000020A-0000-1000-8000-0026BB765291',
|
||||
'0000020F-0000-1000-8000-0026BB765291': 'WiFiSatellite',
|
||||
WiFiSatellite: '0000020F-0000-1000-8000-0026BB765291',
|
||||
'0000022A-0000-1000-8000-0026BB765291': 'WiFiTransport',
|
||||
WiFiTransport: '0000022A-0000-1000-8000-0026BB765291',
|
||||
'0000008B-0000-1000-8000-0026BB765291': 'Window',
|
||||
Window: '0000008B-0000-1000-8000-0026BB765291',
|
||||
'0000008C-0000-1000-8000-0026BB765291': 'WindowCovering',
|
||||
WindowCovering: '0000008C-0000-1000-8000-0026BB765291',
|
||||
} as const
|
||||
|
||||
export const Characteristics = {
|
||||
'00000262-0000-1000-8000-0026BB765291': 'AccessCodeControlPoint',
|
||||
AccessCodeControlPoint: '00000262-0000-1000-8000-0026BB765291',
|
||||
'00000261-0000-1000-8000-0026BB765291': 'AccessCodeSupportedConfiguration',
|
||||
AccessCodeSupportedConfiguration: '00000261-0000-1000-8000-0026BB765291',
|
||||
'000000E5-0000-1000-8000-0026BB765291': 'AccessControlLevel',
|
||||
AccessControlLevel: '000000E5-0000-1000-8000-0026BB765291',
|
||||
'000000A6-0000-1000-8000-0026BB765291': 'AccessoryFlags',
|
||||
AccessoryFlags: '000000A6-0000-1000-8000-0026BB765291',
|
||||
'00000057-0000-1000-8000-0026BB765291': 'AccessoryIdentifier',
|
||||
AccessoryIdentifier: '00000057-0000-1000-8000-0026BB765291',
|
||||
'000000B0-0000-1000-8000-0026BB765291': 'Active',
|
||||
Active: '000000B0-0000-1000-8000-0026BB765291',
|
||||
'000000E7-0000-1000-8000-0026BB765291': 'ActiveIdentifier',
|
||||
ActiveIdentifier: '000000E7-0000-1000-8000-0026BB765291',
|
||||
'0000023B-0000-1000-8000-0026BB765291': 'ActivityInterval',
|
||||
ActivityInterval: '0000023B-0000-1000-8000-0026BB765291',
|
||||
'00000001-0000-1000-8000-0026BB765291': 'AdministratorOnlyAccess',
|
||||
AdministratorOnlyAccess: '00000001-0000-1000-8000-0026BB765291',
|
||||
'00000064-0000-1000-8000-0026BB765291': 'AirParticulateDensity',
|
||||
AirParticulateDensity: '00000064-0000-1000-8000-0026BB765291',
|
||||
'00000065-0000-1000-8000-0026BB765291': 'AirParticulateSize',
|
||||
AirParticulateSize: '00000065-0000-1000-8000-0026BB765291',
|
||||
'0000025B-0000-1000-8000-0026BB765291': 'AirPlayEnable',
|
||||
AirPlayEnable: '0000025B-0000-1000-8000-0026BB765291',
|
||||
'00000095-0000-1000-8000-0026BB765291': 'AirQuality',
|
||||
AirQuality: '00000095-0000-1000-8000-0026BB765291',
|
||||
'000000A4-0000-1000-8000-0026BB765291': 'AppMatchingIdentifier',
|
||||
AppMatchingIdentifier: '000000A4-0000-1000-8000-0026BB765291',
|
||||
'00000269-0000-1000-8000-0026BB765291': 'AssetUpdateReadiness',
|
||||
AssetUpdateReadiness: '00000269-0000-1000-8000-0026BB765291',
|
||||
'00000005-0000-1000-8000-0026BB765291': 'AudioFeedback',
|
||||
AudioFeedback: '00000005-0000-1000-8000-0026BB765291',
|
||||
'00000068-0000-1000-8000-0026BB765291': 'BatteryLevel',
|
||||
BatteryLevel: '00000068-0000-1000-8000-0026BB765291',
|
||||
'00000008-0000-1000-8000-0026BB765291': 'Brightness',
|
||||
Brightness: '00000008-0000-1000-8000-0026BB765291',
|
||||
'00000126-0000-1000-8000-0026BB765291': 'ButtonEvent',
|
||||
ButtonEvent: '00000126-0000-1000-8000-0026BB765291',
|
||||
'0000021D-0000-1000-8000-0026BB765291': 'CameraOperatingModeIndicator',
|
||||
CameraOperatingModeIndicator: '0000021D-0000-1000-8000-0026BB765291',
|
||||
'00000092-0000-1000-8000-0026BB765291': 'CarbonDioxideDetected',
|
||||
CarbonDioxideDetected: '00000092-0000-1000-8000-0026BB765291',
|
||||
'00000093-0000-1000-8000-0026BB765291': 'CarbonDioxideLevel',
|
||||
CarbonDioxideLevel: '00000093-0000-1000-8000-0026BB765291',
|
||||
'00000094-0000-1000-8000-0026BB765291': 'CarbonDioxidePeakLevel',
|
||||
CarbonDioxidePeakLevel: '00000094-0000-1000-8000-0026BB765291',
|
||||
'00000069-0000-1000-8000-0026BB765291': 'CarbonMonoxideDetected',
|
||||
CarbonMonoxideDetected: '00000069-0000-1000-8000-0026BB765291',
|
||||
'00000090-0000-1000-8000-0026BB765291': 'CarbonMonoxideLevel',
|
||||
CarbonMonoxideLevel: '00000090-0000-1000-8000-0026BB765291',
|
||||
'00000091-0000-1000-8000-0026BB765291': 'CarbonMonoxidePeakLevel',
|
||||
CarbonMonoxidePeakLevel: '00000091-0000-1000-8000-0026BB765291',
|
||||
'000000A3-0000-1000-8000-0026BB765291': 'Category',
|
||||
Category: '000000A3-0000-1000-8000-0026BB765291',
|
||||
'00000246-0000-1000-8000-0026BB765291': 'CCAEnergyDetectThreshold',
|
||||
CCAEnergyDetectThreshold: '00000246-0000-1000-8000-0026BB765291',
|
||||
'00000245-0000-1000-8000-0026BB765291': 'CCASignalDetectThreshold',
|
||||
CCASignalDetectThreshold: '00000245-0000-1000-8000-0026BB765291',
|
||||
'0000024B-0000-1000-8000-0026BB765291': 'CharacteristicValueActiveTransitionCount',
|
||||
CharacteristicValueActiveTransitionCount: '0000024B-0000-1000-8000-0026BB765291',
|
||||
'00000143-0000-1000-8000-0026BB765291': 'CharacteristicValueTransitionControl',
|
||||
CharacteristicValueTransitionControl: '00000143-0000-1000-8000-0026BB765291',
|
||||
'0000008F-0000-1000-8000-0026BB765291': 'ChargingState',
|
||||
ChargingState: '0000008F-0000-1000-8000-0026BB765291',
|
||||
'000000DD-0000-1000-8000-0026BB765291': 'ClosedCaptions',
|
||||
ClosedCaptions: '000000DD-0000-1000-8000-0026BB765291',
|
||||
'000000CE-0000-1000-8000-0026BB765291': 'ColorTemperature',
|
||||
ColorTemperature: '000000CE-0000-1000-8000-0026BB765291',
|
||||
'00000263-0000-1000-8000-0026BB765291': 'ConfigurationState',
|
||||
ConfigurationState: '00000263-0000-1000-8000-0026BB765291',
|
||||
'000000A0-0000-1000-8000-0026BB765291': 'ConfigureBridgedAccessory',
|
||||
ConfigureBridgedAccessory: '000000A0-0000-1000-8000-0026BB765291',
|
||||
'0000009D-0000-1000-8000-0026BB765291': 'ConfigureBridgedAccessoryStatus',
|
||||
ConfigureBridgedAccessoryStatus: '0000009D-0000-1000-8000-0026BB765291',
|
||||
'000000E3-0000-1000-8000-0026BB765291': 'ConfiguredName',
|
||||
ConfiguredName: '000000E3-0000-1000-8000-0026BB765291',
|
||||
'0000006A-0000-1000-8000-0026BB765291': 'ContactSensorState',
|
||||
ContactSensorState: '0000006A-0000-1000-8000-0026BB765291',
|
||||
'0000000D-0000-1000-8000-0026BB765291': 'CoolingThresholdTemperature',
|
||||
CoolingThresholdTemperature: '0000000D-0000-1000-8000-0026BB765291',
|
||||
'000000A9-0000-1000-8000-0026BB765291': 'CurrentAirPurifierState',
|
||||
CurrentAirPurifierState: '000000A9-0000-1000-8000-0026BB765291',
|
||||
'0000006B-0000-1000-8000-0026BB765291': 'CurrentAmbientLightLevel',
|
||||
CurrentAmbientLightLevel: '0000006B-0000-1000-8000-0026BB765291',
|
||||
'0000000E-0000-1000-8000-0026BB765291': 'CurrentDoorState',
|
||||
CurrentDoorState: '0000000E-0000-1000-8000-0026BB765291',
|
||||
'000000AF-0000-1000-8000-0026BB765291': 'CurrentFanState',
|
||||
CurrentFanState: '000000AF-0000-1000-8000-0026BB765291',
|
||||
'000000B1-0000-1000-8000-0026BB765291': 'CurrentHeaterCoolerState',
|
||||
CurrentHeaterCoolerState: '000000B1-0000-1000-8000-0026BB765291',
|
||||
'0000000F-0000-1000-8000-0026BB765291': 'CurrentHeatingCoolingState',
|
||||
CurrentHeatingCoolingState: '0000000F-0000-1000-8000-0026BB765291',
|
||||
'0000006C-0000-1000-8000-0026BB765291': 'CurrentHorizontalTiltAngle',
|
||||
CurrentHorizontalTiltAngle: '0000006C-0000-1000-8000-0026BB765291',
|
||||
'000000B3-0000-1000-8000-0026BB765291': 'CurrentHumidifierDehumidifierState',
|
||||
CurrentHumidifierDehumidifierState: '000000B3-0000-1000-8000-0026BB765291',
|
||||
'000000E0-0000-1000-8000-0026BB765291': 'CurrentMediaState',
|
||||
CurrentMediaState: '000000E0-0000-1000-8000-0026BB765291',
|
||||
'0000006D-0000-1000-8000-0026BB765291': 'CurrentPosition',
|
||||
CurrentPosition: '0000006D-0000-1000-8000-0026BB765291',
|
||||
'00000010-0000-1000-8000-0026BB765291': 'CurrentRelativeHumidity',
|
||||
CurrentRelativeHumidity: '00000010-0000-1000-8000-0026BB765291',
|
||||
'000000AA-0000-1000-8000-0026BB765291': 'CurrentSlatState',
|
||||
CurrentSlatState: '000000AA-0000-1000-8000-0026BB765291',
|
||||
'00000011-0000-1000-8000-0026BB765291': 'CurrentTemperature',
|
||||
CurrentTemperature: '00000011-0000-1000-8000-0026BB765291',
|
||||
'000000C1-0000-1000-8000-0026BB765291': 'CurrentTiltAngle',
|
||||
CurrentTiltAngle: '000000C1-0000-1000-8000-0026BB765291',
|
||||
'0000009B-0000-1000-8000-0026BB765291': 'CurrentTime',
|
||||
CurrentTime: '0000009B-0000-1000-8000-0026BB765291',
|
||||
'0000022B-0000-1000-8000-0026BB765291': 'CurrentTransport',
|
||||
CurrentTransport: '0000022B-0000-1000-8000-0026BB765291',
|
||||
'0000006E-0000-1000-8000-0026BB765291': 'CurrentVerticalTiltAngle',
|
||||
CurrentVerticalTiltAngle: '0000006E-0000-1000-8000-0026BB765291',
|
||||
'00000135-0000-1000-8000-0026BB765291': 'CurrentVisibilityState',
|
||||
CurrentVisibilityState: '00000135-0000-1000-8000-0026BB765291',
|
||||
'00000138-0000-1000-8000-0026BB765291': 'DataStreamHAPTransport',
|
||||
DataStreamHAPTransport: '00000138-0000-1000-8000-0026BB765291',
|
||||
'00000139-0000-1000-8000-0026BB765291': 'DataStreamHAPTransportInterrupt',
|
||||
DataStreamHAPTransportInterrupt: '00000139-0000-1000-8000-0026BB765291',
|
||||
'00000098-0000-1000-8000-0026BB765291': 'DayoftheWeek',
|
||||
DayoftheWeek: '00000098-0000-1000-8000-0026BB765291',
|
||||
'00000224-0000-1000-8000-0026BB765291': 'DiagonalFieldOfView',
|
||||
DiagonalFieldOfView: '00000224-0000-1000-8000-0026BB765291',
|
||||
'0000011D-0000-1000-8000-0026BB765291': 'DigitalZoom',
|
||||
DigitalZoom: '0000011D-0000-1000-8000-0026BB765291',
|
||||
'0000009E-0000-1000-8000-0026BB765291': 'DiscoverBridgedAccessories',
|
||||
DiscoverBridgedAccessories: '0000009E-0000-1000-8000-0026BB765291',
|
||||
'0000009F-0000-1000-8000-0026BB765291': 'DiscoveredBridgedAccessories',
|
||||
DiscoveredBridgedAccessories: '0000009F-0000-1000-8000-0026BB765291',
|
||||
'00000136-0000-1000-8000-0026BB765291': 'DisplayOrder',
|
||||
DisplayOrder: '00000136-0000-1000-8000-0026BB765291',
|
||||
'0000023D-0000-1000-8000-0026BB765291': 'EventRetransmissionMaximum',
|
||||
EventRetransmissionMaximum: '0000023D-0000-1000-8000-0026BB765291',
|
||||
'00000223-0000-1000-8000-0026BB765291': 'EventSnapshotsActive',
|
||||
EventSnapshotsActive: '00000223-0000-1000-8000-0026BB765291',
|
||||
'0000023E-0000-1000-8000-0026BB765291': 'EventTransmissionCounters',
|
||||
EventTransmissionCounters: '0000023E-0000-1000-8000-0026BB765291',
|
||||
'000000AC-0000-1000-8000-0026BB765291': 'FilterChangeIndication',
|
||||
FilterChangeIndication: '000000AC-0000-1000-8000-0026BB765291',
|
||||
'000000AB-0000-1000-8000-0026BB765291': 'FilterLifeLevel',
|
||||
FilterLifeLevel: '000000AB-0000-1000-8000-0026BB765291',
|
||||
'00000052-0000-1000-8000-0026BB765291': 'FirmwareRevision',
|
||||
FirmwareRevision: '00000052-0000-1000-8000-0026BB765291',
|
||||
'00000234-0000-1000-8000-0026BB765291': 'FirmwareUpdateReadiness',
|
||||
FirmwareUpdateReadiness: '00000234-0000-1000-8000-0026BB765291',
|
||||
'00000235-0000-1000-8000-0026BB765291': 'FirmwareUpdateStatus',
|
||||
FirmwareUpdateStatus: '00000235-0000-1000-8000-0026BB765291',
|
||||
'0000026C-0000-1000-8000-0026BB765291': 'HardwareFinish',
|
||||
HardwareFinish: '0000026C-0000-1000-8000-0026BB765291',
|
||||
'00000053-0000-1000-8000-0026BB765291': 'HardwareRevision',
|
||||
HardwareRevision: '00000053-0000-1000-8000-0026BB765291',
|
||||
'0000024A-0000-1000-8000-0026BB765291': 'HeartBeat',
|
||||
HeartBeat: '0000024A-0000-1000-8000-0026BB765291',
|
||||
'00000012-0000-1000-8000-0026BB765291': 'HeatingThresholdTemperature',
|
||||
HeatingThresholdTemperature: '00000012-0000-1000-8000-0026BB765291',
|
||||
'0000006F-0000-1000-8000-0026BB765291': 'HoldPosition',
|
||||
HoldPosition: '0000006F-0000-1000-8000-0026BB765291',
|
||||
'0000021B-0000-1000-8000-0026BB765291': 'HomeKitCameraActive',
|
||||
HomeKitCameraActive: '0000021B-0000-1000-8000-0026BB765291',
|
||||
'00000013-0000-1000-8000-0026BB765291': 'Hue',
|
||||
Hue: '00000013-0000-1000-8000-0026BB765291',
|
||||
'000000E6-0000-1000-8000-0026BB765291': 'Identifier',
|
||||
Identifier: '000000E6-0000-1000-8000-0026BB765291',
|
||||
'00000014-0000-1000-8000-0026BB765291': 'Identify',
|
||||
Identify: '00000014-0000-1000-8000-0026BB765291',
|
||||
'0000011F-0000-1000-8000-0026BB765291': 'ImageMirroring',
|
||||
ImageMirroring: '0000011F-0000-1000-8000-0026BB765291',
|
||||
'0000011E-0000-1000-8000-0026BB765291': 'ImageRotation',
|
||||
ImageRotation: '0000011E-0000-1000-8000-0026BB765291',
|
||||
'000000DC-0000-1000-8000-0026BB765291': 'InputDeviceType',
|
||||
InputDeviceType: '000000DC-0000-1000-8000-0026BB765291',
|
||||
'000000DB-0000-1000-8000-0026BB765291': 'InputSourceType',
|
||||
InputSourceType: '000000DB-0000-1000-8000-0026BB765291',
|
||||
'000000D2-0000-1000-8000-0026BB765291': 'InUse',
|
||||
InUse: '000000D2-0000-1000-8000-0026BB765291',
|
||||
'000000D6-0000-1000-8000-0026BB765291': 'IsConfigured',
|
||||
IsConfigured: '000000D6-0000-1000-8000-0026BB765291',
|
||||
'00000070-0000-1000-8000-0026BB765291': 'LeakDetected',
|
||||
LeakDetected: '00000070-0000-1000-8000-0026BB765291',
|
||||
'0000009C-0000-1000-8000-0026BB765291': 'LinkQuality',
|
||||
LinkQuality: '0000009C-0000-1000-8000-0026BB765291',
|
||||
'00000050-0000-1000-8000-0026BB765291': 'ListPairings',
|
||||
ListPairings: '00000050-0000-1000-8000-0026BB765291',
|
||||
'00000019-0000-1000-8000-0026BB765291': 'LockControlPoint',
|
||||
LockControlPoint: '00000019-0000-1000-8000-0026BB765291',
|
||||
'0000001D-0000-1000-8000-0026BB765291': 'LockCurrentState',
|
||||
LockCurrentState: '0000001D-0000-1000-8000-0026BB765291',
|
||||
'0000001C-0000-1000-8000-0026BB765291': 'LockLastKnownAction',
|
||||
LockLastKnownAction: '0000001C-0000-1000-8000-0026BB765291',
|
||||
'0000001A-0000-1000-8000-0026BB765291': 'LockManagementAutoSecurityTimeout',
|
||||
LockManagementAutoSecurityTimeout: '0000001A-0000-1000-8000-0026BB765291',
|
||||
'000000A7-0000-1000-8000-0026BB765291': 'LockPhysicalControls',
|
||||
LockPhysicalControls: '000000A7-0000-1000-8000-0026BB765291',
|
||||
'0000001E-0000-1000-8000-0026BB765291': 'LockTargetState',
|
||||
LockTargetState: '0000001E-0000-1000-8000-0026BB765291',
|
||||
'0000001F-0000-1000-8000-0026BB765291': 'Logs',
|
||||
Logs: '0000001F-0000-1000-8000-0026BB765291',
|
||||
'00000247-0000-1000-8000-0026BB765291': 'MACRetransmissionMaximum',
|
||||
MACRetransmissionMaximum: '00000247-0000-1000-8000-0026BB765291',
|
||||
'00000248-0000-1000-8000-0026BB765291': 'MACTransmissionCounters',
|
||||
MACTransmissionCounters: '00000248-0000-1000-8000-0026BB765291',
|
||||
'00000215-0000-1000-8000-0026BB765291': 'ManagedNetworkEnable',
|
||||
ManagedNetworkEnable: '00000215-0000-1000-8000-0026BB765291',
|
||||
'00000227-0000-1000-8000-0026BB765291': 'ManuallyDisabled',
|
||||
ManuallyDisabled: '00000227-0000-1000-8000-0026BB765291',
|
||||
'00000020-0000-1000-8000-0026BB765291': 'Manufacturer',
|
||||
Manufacturer: '00000020-0000-1000-8000-0026BB765291',
|
||||
'00000243-0000-1000-8000-0026BB765291': 'MaximumTransmitPower',
|
||||
MaximumTransmitPower: '00000243-0000-1000-8000-0026BB765291',
|
||||
'00000021-0000-1000-8000-0026BB765291': 'Model',
|
||||
Model: '00000021-0000-1000-8000-0026BB765291',
|
||||
'00000022-0000-1000-8000-0026BB765291': 'MotionDetected',
|
||||
MotionDetected: '00000022-0000-1000-8000-0026BB765291',
|
||||
'0000026B-0000-1000-8000-0026BB765291': 'MultifunctionButton',
|
||||
MultifunctionButton: '0000026B-0000-1000-8000-0026BB765291',
|
||||
'0000011A-0000-1000-8000-0026BB765291': 'Mute',
|
||||
Mute: '0000011A-0000-1000-8000-0026BB765291',
|
||||
'00000023-0000-1000-8000-0026BB765291': 'Name',
|
||||
Name: '00000023-0000-1000-8000-0026BB765291',
|
||||
'0000021F-0000-1000-8000-0026BB765291': 'NetworkAccessViolationControl',
|
||||
NetworkAccessViolationControl: '0000021F-0000-1000-8000-0026BB765291',
|
||||
'0000020C-0000-1000-8000-0026BB765291': 'NetworkClientProfileControl',
|
||||
NetworkClientProfileControl: '0000020C-0000-1000-8000-0026BB765291',
|
||||
'0000020D-0000-1000-8000-0026BB765291': 'NetworkClientStatusControl',
|
||||
NetworkClientStatusControl: '0000020D-0000-1000-8000-0026BB765291',
|
||||
'00000264-0000-1000-8000-0026BB765291': 'NFCAccessControlPoint',
|
||||
NFCAccessControlPoint: '00000264-0000-1000-8000-0026BB765291',
|
||||
'00000265-0000-1000-8000-0026BB765291': 'NFCAccessSupportedConfiguration',
|
||||
NFCAccessSupportedConfiguration: '00000265-0000-1000-8000-0026BB765291',
|
||||
'0000011B-0000-1000-8000-0026BB765291': 'NightVision',
|
||||
NightVision: '0000011B-0000-1000-8000-0026BB765291',
|
||||
'000000C4-0000-1000-8000-0026BB765291': 'NitrogenDioxideDensity',
|
||||
NitrogenDioxideDensity: '000000C4-0000-1000-8000-0026BB765291',
|
||||
'00000024-0000-1000-8000-0026BB765291': 'ObstructionDetected',
|
||||
ObstructionDetected: '00000024-0000-1000-8000-0026BB765291',
|
||||
'00000071-0000-1000-8000-0026BB765291': 'OccupancyDetected',
|
||||
OccupancyDetected: '00000071-0000-1000-8000-0026BB765291',
|
||||
'00000025-0000-1000-8000-0026BB765291': 'On',
|
||||
On: '00000025-0000-1000-8000-0026BB765291',
|
||||
'00000232-0000-1000-8000-0026BB765291': 'OperatingStateResponse',
|
||||
OperatingStateResponse: '00000232-0000-1000-8000-0026BB765291',
|
||||
'0000011C-0000-1000-8000-0026BB765291': 'OpticalZoom',
|
||||
OpticalZoom: '0000011C-0000-1000-8000-0026BB765291',
|
||||
'00000026-0000-1000-8000-0026BB765291': 'OutletInUse',
|
||||
OutletInUse: '00000026-0000-1000-8000-0026BB765291',
|
||||
'000000C3-0000-1000-8000-0026BB765291': 'OzoneDensity',
|
||||
OzoneDensity: '000000C3-0000-1000-8000-0026BB765291',
|
||||
'0000004F-0000-1000-8000-0026BB765291': 'PairingFeatures',
|
||||
PairingFeatures: '0000004F-0000-1000-8000-0026BB765291',
|
||||
'0000004C-0000-1000-8000-0026BB765291': 'PairSetup',
|
||||
PairSetup: '0000004C-0000-1000-8000-0026BB765291',
|
||||
'0000004E-0000-1000-8000-0026BB765291': 'PairVerify',
|
||||
PairVerify: '0000004E-0000-1000-8000-0026BB765291',
|
||||
'000000E4-0000-1000-8000-0026BB765291': 'PasswordSetting',
|
||||
PasswordSetting: '000000E4-0000-1000-8000-0026BB765291',
|
||||
'00000225-0000-1000-8000-0026BB765291': 'PeriodicSnapshotsActive',
|
||||
PeriodicSnapshotsActive: '00000225-0000-1000-8000-0026BB765291',
|
||||
'000000E2-0000-1000-8000-0026BB765291': 'PictureMode',
|
||||
PictureMode: '000000E2-0000-1000-8000-0026BB765291',
|
||||
'0000023C-0000-1000-8000-0026BB765291': 'Ping',
|
||||
Ping: '0000023C-0000-1000-8000-0026BB765291',
|
||||
'000000C7-0000-1000-8000-0026BB765291': 'PM10Density',
|
||||
PM10Density: '000000C7-0000-1000-8000-0026BB765291',
|
||||
'000000C6-0000-1000-8000-0026BB765291': 'PM2_5Density',
|
||||
PM2_5Density: '000000C6-0000-1000-8000-0026BB765291',
|
||||
'00000072-0000-1000-8000-0026BB765291': 'PositionState',
|
||||
PositionState: '00000072-0000-1000-8000-0026BB765291',
|
||||
'000000DF-0000-1000-8000-0026BB765291': 'PowerModeSelection',
|
||||
PowerModeSelection: '000000DF-0000-1000-8000-0026BB765291',
|
||||
'00000220-0000-1000-8000-0026BB765291': 'ProductData',
|
||||
ProductData: '00000220-0000-1000-8000-0026BB765291',
|
||||
'00000073-0000-1000-8000-0026BB765291': 'ProgrammableSwitchEvent',
|
||||
ProgrammableSwitchEvent: '00000073-0000-1000-8000-0026BB765291',
|
||||
'00000074-0000-1000-8000-0026BB765291': 'ProgrammableSwitchOutputState',
|
||||
ProgrammableSwitchOutputState: '00000074-0000-1000-8000-0026BB765291',
|
||||
'000000D1-0000-1000-8000-0026BB765291': 'ProgramMode',
|
||||
ProgramMode: '000000D1-0000-1000-8000-0026BB765291',
|
||||
'00000063-0000-1000-8000-0026BB765291': 'Reachable',
|
||||
Reachable: '00000063-0000-1000-8000-0026BB765291',
|
||||
'0000023F-0000-1000-8000-0026BB765291': 'ReceivedSignalStrengthIndication',
|
||||
ReceivedSignalStrengthIndication: '0000023F-0000-1000-8000-0026BB765291',
|
||||
'00000244-0000-1000-8000-0026BB765291': 'ReceiverSensitivity',
|
||||
ReceiverSensitivity: '00000244-0000-1000-8000-0026BB765291',
|
||||
'00000226-0000-1000-8000-0026BB765291': 'RecordingAudioActive',
|
||||
RecordingAudioActive: '00000226-0000-1000-8000-0026BB765291',
|
||||
'000000C9-0000-1000-8000-0026BB765291': 'RelativeHumidityDehumidifierThreshold',
|
||||
RelativeHumidityDehumidifierThreshold: '000000C9-0000-1000-8000-0026BB765291',
|
||||
'000000CA-0000-1000-8000-0026BB765291': 'RelativeHumidityHumidifierThreshold',
|
||||
RelativeHumidityHumidifierThreshold: '000000CA-0000-1000-8000-0026BB765291',
|
||||
'0000005E-0000-1000-8000-0026BB765291': 'RelayControlPoint',
|
||||
RelayControlPoint: '0000005E-0000-1000-8000-0026BB765291',
|
||||
'0000005B-0000-1000-8000-0026BB765291': 'RelayEnabled',
|
||||
RelayEnabled: '0000005B-0000-1000-8000-0026BB765291',
|
||||
'0000005C-0000-1000-8000-0026BB765291': 'RelayState',
|
||||
RelayState: '0000005C-0000-1000-8000-0026BB765291',
|
||||
'000000D4-0000-1000-8000-0026BB765291': 'RemainingDuration',
|
||||
RemainingDuration: '000000D4-0000-1000-8000-0026BB765291',
|
||||
'000000E1-0000-1000-8000-0026BB765291': 'RemoteKey',
|
||||
RemoteKey: '000000E1-0000-1000-8000-0026BB765291',
|
||||
'000000AD-0000-1000-8000-0026BB765291': 'ResetFilterIndication',
|
||||
ResetFilterIndication: '000000AD-0000-1000-8000-0026BB765291',
|
||||
'00000028-0000-1000-8000-0026BB765291': 'RotationDirection',
|
||||
RotationDirection: '00000028-0000-1000-8000-0026BB765291',
|
||||
'00000029-0000-1000-8000-0026BB765291': 'RotationSpeed',
|
||||
RotationSpeed: '00000029-0000-1000-8000-0026BB765291',
|
||||
'0000020E-0000-1000-8000-0026BB765291': 'RouterStatus',
|
||||
RouterStatus: '0000020E-0000-1000-8000-0026BB765291',
|
||||
'0000002F-0000-1000-8000-0026BB765291': 'Saturation',
|
||||
Saturation: '0000002F-0000-1000-8000-0026BB765291',
|
||||
'0000008E-0000-1000-8000-0026BB765291': 'SecuritySystemAlarmType',
|
||||
SecuritySystemAlarmType: '0000008E-0000-1000-8000-0026BB765291',
|
||||
'00000066-0000-1000-8000-0026BB765291': 'SecuritySystemCurrentState',
|
||||
SecuritySystemCurrentState: '00000066-0000-1000-8000-0026BB765291',
|
||||
'00000067-0000-1000-8000-0026BB765291': 'SecuritySystemTargetState',
|
||||
SecuritySystemTargetState: '00000067-0000-1000-8000-0026BB765291',
|
||||
'00000128-0000-1000-8000-0026BB765291': 'SelectedAudioStreamConfiguration',
|
||||
SelectedAudioStreamConfiguration: '00000128-0000-1000-8000-0026BB765291',
|
||||
'00000209-0000-1000-8000-0026BB765291': 'SelectedCameraRecordingConfiguration',
|
||||
SelectedCameraRecordingConfiguration: '00000209-0000-1000-8000-0026BB765291',
|
||||
'0000024D-0000-1000-8000-0026BB765291': 'SelectedDiagnosticsModes',
|
||||
SelectedDiagnosticsModes: '0000024D-0000-1000-8000-0026BB765291',
|
||||
'00000117-0000-1000-8000-0026BB765291': 'SelectedRTPStreamConfiguration',
|
||||
SelectedRTPStreamConfiguration: '00000117-0000-1000-8000-0026BB765291',
|
||||
'00000030-0000-1000-8000-0026BB765291': 'SerialNumber',
|
||||
SerialNumber: '00000030-0000-1000-8000-0026BB765291',
|
||||
'000000CB-0000-1000-8000-0026BB765291': 'ServiceLabelIndex',
|
||||
ServiceLabelIndex: '000000CB-0000-1000-8000-0026BB765291',
|
||||
'000000CD-0000-1000-8000-0026BB765291': 'ServiceLabelNamespace',
|
||||
ServiceLabelNamespace: '000000CD-0000-1000-8000-0026BB765291',
|
||||
'000000D3-0000-1000-8000-0026BB765291': 'SetDuration',
|
||||
SetDuration: '000000D3-0000-1000-8000-0026BB765291',
|
||||
'00000131-0000-1000-8000-0026BB765291': 'SetupDataStreamTransport',
|
||||
SetupDataStreamTransport: '00000131-0000-1000-8000-0026BB765291',
|
||||
'00000118-0000-1000-8000-0026BB765291': 'SetupEndpoints',
|
||||
SetupEndpoints: '00000118-0000-1000-8000-0026BB765291',
|
||||
'00000201-0000-1000-8000-0026BB765291': 'SetupTransferTransport',
|
||||
SetupTransferTransport: '00000201-0000-1000-8000-0026BB765291',
|
||||
'00000241-0000-1000-8000-0026BB765291': 'SignalToNoiseRatio',
|
||||
SignalToNoiseRatio: '00000241-0000-1000-8000-0026BB765291',
|
||||
'00000255-0000-1000-8000-0026BB765291': 'SiriEnable',
|
||||
SiriEnable: '00000255-0000-1000-8000-0026BB765291',
|
||||
'00000254-0000-1000-8000-0026BB765291': 'SiriEndpointSessionStatus',
|
||||
SiriEndpointSessionStatus: '00000254-0000-1000-8000-0026BB765291',
|
||||
'0000025A-0000-1000-8000-0026BB765291': 'SiriEngineVersion',
|
||||
SiriEngineVersion: '0000025A-0000-1000-8000-0026BB765291',
|
||||
'00000132-0000-1000-8000-0026BB765291': 'SiriInputType',
|
||||
SiriInputType: '00000132-0000-1000-8000-0026BB765291',
|
||||
'00000258-0000-1000-8000-0026BB765291': 'SiriLightOnUse',
|
||||
SiriLightOnUse: '00000258-0000-1000-8000-0026BB765291',
|
||||
'00000256-0000-1000-8000-0026BB765291': 'SiriListening',
|
||||
SiriListening: '00000256-0000-1000-8000-0026BB765291',
|
||||
'00000257-0000-1000-8000-0026BB765291': 'SiriTouchToUse',
|
||||
SiriTouchToUse: '00000257-0000-1000-8000-0026BB765291',
|
||||
'000000C0-0000-1000-8000-0026BB765291': 'SlatType',
|
||||
SlatType: '000000C0-0000-1000-8000-0026BB765291',
|
||||
'000000E8-0000-1000-8000-0026BB765291': 'SleepDiscoveryMode',
|
||||
SleepDiscoveryMode: '000000E8-0000-1000-8000-0026BB765291',
|
||||
'0000023A-0000-1000-8000-0026BB765291': 'SleepInterval',
|
||||
SleepInterval: '0000023A-0000-1000-8000-0026BB765291',
|
||||
'00000076-0000-1000-8000-0026BB765291': 'SmokeDetected',
|
||||
SmokeDetected: '00000076-0000-1000-8000-0026BB765291',
|
||||
'00000054-0000-1000-8000-0026BB765291': 'SoftwareRevision',
|
||||
SoftwareRevision: '00000054-0000-1000-8000-0026BB765291',
|
||||
'00000249-0000-1000-8000-0026BB765291': 'StagedFirmwareVersion',
|
||||
StagedFirmwareVersion: '00000249-0000-1000-8000-0026BB765291',
|
||||
'00000075-0000-1000-8000-0026BB765291': 'StatusActive',
|
||||
StatusActive: '00000075-0000-1000-8000-0026BB765291',
|
||||
'00000077-0000-1000-8000-0026BB765291': 'StatusFault',
|
||||
StatusFault: '00000077-0000-1000-8000-0026BB765291',
|
||||
'00000078-0000-1000-8000-0026BB765291': 'StatusJammed',
|
||||
StatusJammed: '00000078-0000-1000-8000-0026BB765291',
|
||||
'00000079-0000-1000-8000-0026BB765291': 'StatusLowBattery',
|
||||
StatusLowBattery: '00000079-0000-1000-8000-0026BB765291',
|
||||
'0000007A-0000-1000-8000-0026BB765291': 'StatusTampered',
|
||||
StatusTampered: '0000007A-0000-1000-8000-0026BB765291',
|
||||
'00000120-0000-1000-8000-0026BB765291': 'StreamingStatus',
|
||||
StreamingStatus: '00000120-0000-1000-8000-0026BB765291',
|
||||
'000000C5-0000-1000-8000-0026BB765291': 'SulphurDioxideDensity',
|
||||
SulphurDioxideDensity: '000000C5-0000-1000-8000-0026BB765291',
|
||||
'00000268-0000-1000-8000-0026BB765291': 'SupportedAssetTypes',
|
||||
SupportedAssetTypes: '00000268-0000-1000-8000-0026BB765291',
|
||||
'00000207-0000-1000-8000-0026BB765291': 'SupportedAudioRecordingConfiguration',
|
||||
SupportedAudioRecordingConfiguration: '00000207-0000-1000-8000-0026BB765291',
|
||||
'00000115-0000-1000-8000-0026BB765291': 'SupportedAudioStreamConfiguration',
|
||||
SupportedAudioStreamConfiguration: '00000115-0000-1000-8000-0026BB765291',
|
||||
'00000205-0000-1000-8000-0026BB765291': 'SupportedCameraRecordingConfiguration',
|
||||
SupportedCameraRecordingConfiguration: '00000205-0000-1000-8000-0026BB765291',
|
||||
'00000144-0000-1000-8000-0026BB765291': 'SupportedCharacteristicValueTransitionConfiguration',
|
||||
SupportedCharacteristicValueTransitionConfiguration: '00000144-0000-1000-8000-0026BB765291',
|
||||
'00000130-0000-1000-8000-0026BB765291': 'SupportedDataStreamTransportConfiguration',
|
||||
SupportedDataStreamTransportConfiguration: '00000130-0000-1000-8000-0026BB765291',
|
||||
'0000024C-0000-1000-8000-0026BB765291': 'SupportedDiagnosticsModes',
|
||||
SupportedDiagnosticsModes: '0000024C-0000-1000-8000-0026BB765291',
|
||||
'00000238-0000-1000-8000-0026BB765291': 'SupportedDiagnosticsSnapshot',
|
||||
SupportedDiagnosticsSnapshot: '00000238-0000-1000-8000-0026BB765291',
|
||||
'00000233-0000-1000-8000-0026BB765291': 'SupportedFirmwareUpdateConfiguration',
|
||||
SupportedFirmwareUpdateConfiguration: '00000233-0000-1000-8000-0026BB765291',
|
||||
'00000210-0000-1000-8000-0026BB765291': 'SupportedRouterConfiguration',
|
||||
SupportedRouterConfiguration: '00000210-0000-1000-8000-0026BB765291',
|
||||
'00000116-0000-1000-8000-0026BB765291': 'SupportedRTPConfiguration',
|
||||
SupportedRTPConfiguration: '00000116-0000-1000-8000-0026BB765291',
|
||||
'00000202-0000-1000-8000-0026BB765291': 'SupportedTransferTransportConfiguration',
|
||||
SupportedTransferTransportConfiguration: '00000202-0000-1000-8000-0026BB765291',
|
||||
'00000206-0000-1000-8000-0026BB765291': 'SupportedVideoRecordingConfiguration',
|
||||
SupportedVideoRecordingConfiguration: '00000206-0000-1000-8000-0026BB765291',
|
||||
'00000114-0000-1000-8000-0026BB765291': 'SupportedVideoStreamConfiguration',
|
||||
SupportedVideoStreamConfiguration: '00000114-0000-1000-8000-0026BB765291',
|
||||
'000000B6-0000-1000-8000-0026BB765291': 'SwingMode',
|
||||
SwingMode: '000000B6-0000-1000-8000-0026BB765291',
|
||||
'000000A8-0000-1000-8000-0026BB765291': 'TargetAirPurifierState',
|
||||
TargetAirPurifierState: '000000A8-0000-1000-8000-0026BB765291',
|
||||
'000000AE-0000-1000-8000-0026BB765291': 'TargetAirQuality',
|
||||
TargetAirQuality: '000000AE-0000-1000-8000-0026BB765291',
|
||||
'00000124-0000-1000-8000-0026BB765291': 'TargetControlList',
|
||||
TargetControlList: '00000124-0000-1000-8000-0026BB765291',
|
||||
'00000123-0000-1000-8000-0026BB765291': 'TargetControlSupportedConfiguration',
|
||||
TargetControlSupportedConfiguration: '00000123-0000-1000-8000-0026BB765291',
|
||||
'00000032-0000-1000-8000-0026BB765291': 'TargetDoorState',
|
||||
TargetDoorState: '00000032-0000-1000-8000-0026BB765291',
|
||||
'000000BF-0000-1000-8000-0026BB765291': 'TargetFanState',
|
||||
TargetFanState: '000000BF-0000-1000-8000-0026BB765291',
|
||||
'000000B2-0000-1000-8000-0026BB765291': 'TargetHeaterCoolerState',
|
||||
TargetHeaterCoolerState: '000000B2-0000-1000-8000-0026BB765291',
|
||||
'00000033-0000-1000-8000-0026BB765291': 'TargetHeatingCoolingState',
|
||||
TargetHeatingCoolingState: '00000033-0000-1000-8000-0026BB765291',
|
||||
'0000007B-0000-1000-8000-0026BB765291': 'TargetHorizontalTiltAngle',
|
||||
TargetHorizontalTiltAngle: '0000007B-0000-1000-8000-0026BB765291',
|
||||
'000000B4-0000-1000-8000-0026BB765291': 'TargetHumidifierDehumidifierState',
|
||||
TargetHumidifierDehumidifierState: '000000B4-0000-1000-8000-0026BB765291',
|
||||
'00000137-0000-1000-8000-0026BB765291': 'TargetMediaState',
|
||||
TargetMediaState: '00000137-0000-1000-8000-0026BB765291',
|
||||
'0000007C-0000-1000-8000-0026BB765291': 'TargetPosition',
|
||||
TargetPosition: '0000007C-0000-1000-8000-0026BB765291',
|
||||
'00000034-0000-1000-8000-0026BB765291': 'TargetRelativeHumidity',
|
||||
TargetRelativeHumidity: '00000034-0000-1000-8000-0026BB765291',
|
||||
'000000BE-0000-1000-8000-0026BB765291': 'TargetSlatState',
|
||||
TargetSlatState: '000000BE-0000-1000-8000-0026BB765291',
|
||||
'00000035-0000-1000-8000-0026BB765291': 'TargetTemperature',
|
||||
TargetTemperature: '00000035-0000-1000-8000-0026BB765291',
|
||||
'000000C2-0000-1000-8000-0026BB765291': 'TargetTiltAngle',
|
||||
TargetTiltAngle: '000000C2-0000-1000-8000-0026BB765291',
|
||||
'0000007D-0000-1000-8000-0026BB765291': 'TargetVerticalTiltAngle',
|
||||
TargetVerticalTiltAngle: '0000007D-0000-1000-8000-0026BB765291',
|
||||
'00000134-0000-1000-8000-0026BB765291': 'TargetVisibilityState',
|
||||
TargetVisibilityState: '00000134-0000-1000-8000-0026BB765291',
|
||||
'00000036-0000-1000-8000-0026BB765291': 'TemperatureDisplayUnits',
|
||||
TemperatureDisplayUnits: '00000036-0000-1000-8000-0026BB765291',
|
||||
'0000021C-0000-1000-8000-0026BB765291': 'ThirdPartyCameraActive',
|
||||
ThirdPartyCameraActive: '0000021C-0000-1000-8000-0026BB765291',
|
||||
'00000704-0000-1000-8000-0026BB765291': 'ThreadControlPoint',
|
||||
ThreadControlPoint: '00000704-0000-1000-8000-0026BB765291',
|
||||
'00000702-0000-1000-8000-0026BB765291': 'ThreadNodeCapabilities',
|
||||
ThreadNodeCapabilities: '00000702-0000-1000-8000-0026BB765291',
|
||||
'00000706-0000-1000-8000-0026BB765291': 'ThreadOpenThreadVersion',
|
||||
ThreadOpenThreadVersion: '00000706-0000-1000-8000-0026BB765291',
|
||||
'00000703-0000-1000-8000-0026BB765291': 'ThreadStatus',
|
||||
ThreadStatus: '00000703-0000-1000-8000-0026BB765291',
|
||||
'0000009A-0000-1000-8000-0026BB765291': 'TimeUpdate',
|
||||
TimeUpdate: '0000009A-0000-1000-8000-0026BB765291',
|
||||
'00000242-0000-1000-8000-0026BB765291': 'TransmitPower',
|
||||
TransmitPower: '00000242-0000-1000-8000-0026BB765291',
|
||||
'00000061-0000-1000-8000-0026BB765291': 'TunnelConnectionTimeout',
|
||||
TunnelConnectionTimeout: '00000061-0000-1000-8000-0026BB765291',
|
||||
'00000060-0000-1000-8000-0026BB765291': 'TunneledAccessoryAdvertising',
|
||||
TunneledAccessoryAdvertising: '00000060-0000-1000-8000-0026BB765291',
|
||||
'00000059-0000-1000-8000-0026BB765291': 'TunneledAccessoryConnected',
|
||||
TunneledAccessoryConnected: '00000059-0000-1000-8000-0026BB765291',
|
||||
'00000058-0000-1000-8000-0026BB765291': 'TunneledAccessoryStateNumber',
|
||||
TunneledAccessoryStateNumber: '00000058-0000-1000-8000-0026BB765291',
|
||||
'000000D5-0000-1000-8000-0026BB765291': 'ValveType',
|
||||
ValveType: '000000D5-0000-1000-8000-0026BB765291',
|
||||
'00000037-0000-1000-8000-0026BB765291': 'Version',
|
||||
Version: '00000037-0000-1000-8000-0026BB765291',
|
||||
'00000229-0000-1000-8000-0026BB765291': 'VideoAnalysisActive',
|
||||
VideoAnalysisActive: '00000229-0000-1000-8000-0026BB765291',
|
||||
'000000C8-0000-1000-8000-0026BB765291': 'VOCDensity',
|
||||
VOCDensity: '000000C8-0000-1000-8000-0026BB765291',
|
||||
'00000119-0000-1000-8000-0026BB765291': 'Volume',
|
||||
Volume: '00000119-0000-1000-8000-0026BB765291',
|
||||
'000000E9-0000-1000-8000-0026BB765291': 'VolumeControlType',
|
||||
VolumeControlType: '000000E9-0000-1000-8000-0026BB765291',
|
||||
'000000EA-0000-1000-8000-0026BB765291': 'VolumeSelector',
|
||||
VolumeSelector: '000000EA-0000-1000-8000-0026BB765291',
|
||||
'00000222-0000-1000-8000-0026BB765291': 'WakeConfiguration',
|
||||
WakeConfiguration: '00000222-0000-1000-8000-0026BB765291',
|
||||
'00000211-0000-1000-8000-0026BB765291': 'WANConfigurationList',
|
||||
WANConfigurationList: '00000211-0000-1000-8000-0026BB765291',
|
||||
'00000212-0000-1000-8000-0026BB765291': 'WANStatusList',
|
||||
WANStatusList: '00000212-0000-1000-8000-0026BB765291',
|
||||
'000000B5-0000-1000-8000-0026BB765291': 'WaterLevel',
|
||||
WaterLevel: '000000B5-0000-1000-8000-0026BB765291',
|
||||
'0000022C-0000-1000-8000-0026BB765291': 'WiFiCapabilities',
|
||||
WiFiCapabilities: '0000022C-0000-1000-8000-0026BB765291',
|
||||
'0000022D-0000-1000-8000-0026BB765291': 'WiFiConfigurationControl',
|
||||
WiFiConfigurationControl: '0000022D-0000-1000-8000-0026BB765291',
|
||||
'0000021E-0000-1000-8000-0026BB765291': 'WiFiSatelliteStatus',
|
||||
WiFiSatelliteStatus: '0000021E-0000-1000-8000-0026BB765291',
|
||||
} as const
|
||||
|
||||
export const Categories = {
|
||||
OTHER: 1,
|
||||
BRIDGE: 2,
|
||||
FAN: 3,
|
||||
GARAGE_DOOR_OPENER: 4,
|
||||
LIGHTBULB: 5,
|
||||
DOOR_LOCK: 6,
|
||||
OUTLET: 7,
|
||||
SWITCH: 8,
|
||||
THERMOSTAT: 9,
|
||||
SENSOR: 10,
|
||||
ALARM_SYSTEM: 11,
|
||||
SECURITY_SYSTEM: 11,
|
||||
DOOR: 12,
|
||||
WINDOW: 13,
|
||||
WINDOW_COVERING: 14,
|
||||
PROGRAMMABLE_SWITCH: 15,
|
||||
RANGE_EXTENDER: 16,
|
||||
CAMERA: 17,
|
||||
IP_CAMERA: 17,
|
||||
VIDEO_DOORBELL: 18,
|
||||
AIR_PURIFIER: 19,
|
||||
AIR_HEATER: 20,
|
||||
AIR_CONDITIONER: 21,
|
||||
AIR_HUMIDIFIER: 22,
|
||||
AIR_DEHUMIDIFIER: 23,
|
||||
APPLE_TV: 24,
|
||||
HOMEPOD: 25,
|
||||
SPEAKER: 26,
|
||||
AIRPORT: 27,
|
||||
SPRINKLER: 28,
|
||||
FAUCET: 29,
|
||||
SHOWER_HEAD: 30,
|
||||
TELEVISION: 31,
|
||||
TARGET_CONTROLLER: 32,
|
||||
ROUTER: 33,
|
||||
AUDIO_RECEIVER: 34,
|
||||
TV_SET_TOP_BOX: 35,
|
||||
TV_STREAMING_STICK: 36,
|
||||
} as const
|
22
src/http/api.ts
Normal file
22
src/http/api.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { Logger } from 'homebridge'
|
||||
|
||||
export type HttpResponse = {
|
||||
statusCode: number
|
||||
body: string
|
||||
headers: Record<string, string>
|
||||
}
|
||||
|
||||
export type HttpServerConfig = {
|
||||
port: number
|
||||
requestInterceptor: () => HttpResponse | undefined
|
||||
probeController: () => HttpResponse
|
||||
notFoundController: () => HttpResponse
|
||||
errorController: () => HttpResponse
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export type HttpServerController = {
|
||||
shutdown(): void
|
||||
}
|
||||
|
||||
export type HttpServer = (config: HttpServerConfig) => Promise<HttpServerController>
|
82
src/http/fastify.ts
Normal file
82
src/http/fastify.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import Fastify, { FastifyBaseLogger, FastifyReply, FastifyRequest, HookHandlerDoneFunction } from 'fastify'
|
||||
import { HttpResponse, HttpServer } from './api'
|
||||
import { Logger } from 'homebridge'
|
||||
import { Bindings, ChildLoggerOptions } from 'fastify/types/logger'
|
||||
import { LogFn } from 'pino'
|
||||
|
||||
/*class PinoLoggerBridge implements FastifyBaseLogger {
|
||||
|
||||
constructor(private readonly logger: Logger) {
|
||||
}
|
||||
|
||||
child(bindings: Bindings, options: ChildLoggerOptions | undefined): FastifyBaseLogger {
|
||||
return this
|
||||
}
|
||||
|
||||
debug(m: string|unknown, ...args: unknown[]) {
|
||||
this.logger.debug(typeof m === 'string' ? m : JSON.stringify(m), ...args)
|
||||
}
|
||||
|
||||
error: LogFn;
|
||||
fatal: pino.LogFn;
|
||||
info: pino.LogFn;
|
||||
level: pino.LevelWithSilent | string;
|
||||
silent: pino.LogFn;
|
||||
trace: pino.LogFn;
|
||||
warn: pino.LogFn;
|
||||
}*/
|
||||
|
||||
function adaptResponseToReply(response: HttpResponse, reply: FastifyReply): void {
|
||||
if (response.statusCode) {
|
||||
reply.code(response.statusCode)
|
||||
}
|
||||
if (response.body) {
|
||||
reply.send(response.body)
|
||||
}
|
||||
|
||||
if (response.headers) {
|
||||
reply.headers(response.headers)
|
||||
}
|
||||
}
|
||||
|
||||
export const serve: HttpServer = async ({
|
||||
port,
|
||||
requestInterceptor,
|
||||
probeController,
|
||||
notFoundController,
|
||||
errorController,
|
||||
}) => {
|
||||
const fastify = Fastify({
|
||||
// logger
|
||||
})
|
||||
|
||||
fastify.addHook('onRequest', (request: FastifyRequest, reply: FastifyReply, next: HookHandlerDoneFunction) => {
|
||||
const response = requestInterceptor()
|
||||
|
||||
if (response) {
|
||||
adaptResponseToReply(response, reply)
|
||||
}
|
||||
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async (error, request: FastifyRequest, reply: FastifyReply) => {
|
||||
adaptResponseToReply(errorController(), reply)
|
||||
})
|
||||
|
||||
fastify.setNotFoundHandler(async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
adaptResponseToReply(notFoundController(), reply)
|
||||
})
|
||||
|
||||
fastify.get('/probe', async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
adaptResponseToReply(probeController(), reply)
|
||||
})
|
||||
|
||||
await fastify.listen({ port })
|
||||
|
||||
return {
|
||||
shutdown() {
|
||||
fastify.close()
|
||||
},
|
||||
}
|
||||
}
|
15
src/index.ts
15
src/index.ts
|
@ -1,11 +1,8 @@
|
|||
import { API } from 'homebridge';
|
||||
import { API } from 'homebridge'
|
||||
|
||||
import { PLATFORM_NAME } from './settings';
|
||||
import { ExampleHomebridgePlatform } from './platform';
|
||||
import { PLATFORM_NAME } from './settings'
|
||||
import { PrometheusExporterPlatform } from './platform'
|
||||
|
||||
/**
|
||||
* This method registers the platform with Homebridge
|
||||
*/
|
||||
export = (api: API) => {
|
||||
api.registerPlatform(PLATFORM_NAME, ExampleHomebridgePlatform);
|
||||
};
|
||||
export = (api: API): void => {
|
||||
api.registerPlatform(PLATFORM_NAME, PrometheusExporterPlatform)
|
||||
}
|
||||
|
|
138
src/metrics.ts
Normal file
138
src/metrics.ts
Normal file
|
@ -0,0 +1,138 @@
|
|||
import type { Device, Accessory, NumberTypes, Service } from './boundaries'
|
||||
import { isType } from './std'
|
||||
import { NUMBER_TYPES } from './boundaries'
|
||||
|
||||
import { Services } from './hap'
|
||||
|
||||
export class Metric {
|
||||
constructor(
|
||||
public readonly name: string,
|
||||
public readonly value: number,
|
||||
public readonly type: NumberTypes,
|
||||
public readonly labels: Record<string, string>,
|
||||
) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Characteristics that would be nonsensical to report as metrics
|
||||
*/
|
||||
const METRICS_FILTER = ['Identifier']
|
||||
|
||||
function debug(devices: Device[]): void {
|
||||
const debugInfo = []
|
||||
|
||||
for (const device of devices) {
|
||||
for (const accessory of device.accessories.accessories) {
|
||||
for (const service of accessory.services) {
|
||||
const info = []
|
||||
for (const characteristic of service.characteristics) {
|
||||
info.push(
|
||||
[characteristic.description, 'value' in characteristic ? characteristic.value : '<none>'].join(
|
||||
': ',
|
||||
),
|
||||
)
|
||||
}
|
||||
debugInfo.push(['Service ' + Services[service.type as keyof typeof Services], info])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(debugInfo, null, 4))
|
||||
}
|
||||
|
||||
export function aggregate(devices: Device[]): Metric[] {
|
||||
const metrics: Metric[] = []
|
||||
|
||||
for (const device of devices) {
|
||||
for (const accessory of device.accessories.accessories) {
|
||||
for (const service of accessory.services) {
|
||||
const labels = {
|
||||
...getDeviceLabels(device),
|
||||
...getAccessoryLabels(accessory),
|
||||
...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(
|
||||
Services[service.type as keyof typeof Services],
|
||||
characteristic.description,
|
||||
characteristic.unit,
|
||||
)
|
||||
if (!METRICS_FILTER.includes(name)) {
|
||||
metrics.push(new Metric(name, characteristic.value, characteristic.format, labels))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metrics
|
||||
}
|
||||
|
||||
export function formatName(serviceName: string, description: string, unit: string | undefined = undefined): string {
|
||||
return (
|
||||
[serviceName, description, typeof unit === 'string' ? unit.toLowerCase() : undefined]
|
||||
.filter(isType('string'))
|
||||
.map((v) => camelCaseToSnakeCase(v))
|
||||
// Remove duplicate prefix
|
||||
.reduce((carry, value) => (value.startsWith(carry) ? value : carry + '_' + value))
|
||||
)
|
||||
}
|
||||
|
||||
function camelCaseToSnakeCase(str: string): string {
|
||||
return str
|
||||
.replace(/\B([A-Z][a-z])/g, ' $1')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/\s+/g, '_')
|
||||
}
|
||||
|
||||
function getDeviceLabels(device: Device): Record<string, string> {
|
||||
return {
|
||||
bridge: device.instance.name,
|
||||
instance: device.instance.url,
|
||||
device_id: device.instance.deviceID,
|
||||
}
|
||||
}
|
||||
|
||||
function getAccessoryLabels(accessory: Accessory): Record<string, string> {
|
||||
const labels: Record<string, string> = {}
|
||||
|
||||
for (const service of accessory.services) {
|
||||
if (service.type === '0000003E-0000-1000-8000-0026BB765291') {
|
||||
return getServiceLabels(service)
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
function getServiceLabels(service: Service): Record<string, string> {
|
||||
const labels: Record<string, string> = {}
|
||||
|
||||
for (const characteristic of service.characteristics) {
|
||||
if (
|
||||
characteristic.format === 'string' &&
|
||||
[
|
||||
'Name',
|
||||
'Configured Name',
|
||||
'Model',
|
||||
'Manufacturer',
|
||||
'Serial Number',
|
||||
'Version',
|
||||
'Firmware Revision',
|
||||
'Hardware Revision',
|
||||
].includes(characteristic.description)
|
||||
) {
|
||||
labels[camelCaseToSnakeCase(characteristic.description)] = characteristic.value
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
218
src/platform.ts
218
src/platform.ts
|
@ -1,116 +1,120 @@
|
|||
import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
|
||||
import { API, Logger, PlatformConfig, IndependentPlatformPlugin } from 'homebridge'
|
||||
|
||||
import { PLATFORM_NAME, PLUGIN_NAME } from './settings';
|
||||
import { ExamplePlatformAccessory } from './platformAccessory';
|
||||
import { Metric, aggregate } from './metrics'
|
||||
import { discover } from './discovery/hap_node_js_client'
|
||||
import { serve } from './http/fastify'
|
||||
import { HttpServerController } from './http/api'
|
||||
|
||||
/**
|
||||
* HomebridgePlatform
|
||||
* This class is the main constructor for your plugin, this is where you should
|
||||
* parse the user config and discover/register accessories with Homebridge.
|
||||
*/
|
||||
export class ExampleHomebridgePlatform implements DynamicPlatformPlugin {
|
||||
public readonly Service: typeof Service = this.api.hap.Service;
|
||||
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
|
||||
export class PrometheusExporterPlatform implements IndependentPlatformPlugin {
|
||||
private metrics: Metric[] = []
|
||||
private metricsDiscovered = false
|
||||
private http: HttpServerController | undefined = undefined
|
||||
|
||||
// this is used to track restored cached accessories
|
||||
public readonly accessories: PlatformAccessory[] = [];
|
||||
constructor(public readonly log: Logger, public readonly config: PlatformConfig, public readonly api: API) {
|
||||
this.log.debug('Initializing platform %s', this.config.platform)
|
||||
|
||||
constructor(
|
||||
public readonly log: Logger,
|
||||
public readonly config: PlatformConfig,
|
||||
public readonly api: API,
|
||||
) {
|
||||
this.log.debug('Finished initializing platform:', this.config.name);
|
||||
this.configure()
|
||||
|
||||
// When this event is fired it means Homebridge has restored all cached accessories from disk.
|
||||
// Dynamic Platform plugins should only register new accessories after this event was fired,
|
||||
// in order to ensure they weren't added to homebridge already. This event can also be used
|
||||
// to start discovery of new accessories.
|
||||
this.api.on('didFinishLaunching', () => {
|
||||
log.debug('Executed didFinishLaunching callback');
|
||||
// run the method to discover / register your devices as accessories
|
||||
this.discoverDevices();
|
||||
});
|
||||
}
|
||||
this.api.on('shutdown', () => {
|
||||
this.log.debug('Shutting down %s', this.config.platform)
|
||||
if (this.http) {
|
||||
this.http.shutdown()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* This function is invoked when homebridge restores cached accessories from disk at startup.
|
||||
* It should be used to setup event handlers for characteristics and update respective values.
|
||||
*/
|
||||
configureAccessory(accessory: PlatformAccessory) {
|
||||
this.log.info('Loading accessory from cache:', accessory.displayName);
|
||||
this.startHttpServer()
|
||||
|
||||
// add the restored accessory to the accessories cache so we can track if it has already been registered
|
||||
this.accessories.push(accessory);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an example method showing how to register discovered accessories.
|
||||
* Accessories must only be registered once, previously created accessories
|
||||
* must not be registered again to prevent "duplicate UUID" errors.
|
||||
*/
|
||||
discoverDevices() {
|
||||
|
||||
// EXAMPLE ONLY
|
||||
// A real plugin you would discover accessories from the local network, cloud services
|
||||
// or a user-defined array in the platform config.
|
||||
const exampleDevices = [
|
||||
{
|
||||
exampleUniqueId: 'ABCD',
|
||||
exampleDisplayName: 'Bedroom',
|
||||
},
|
||||
{
|
||||
exampleUniqueId: 'EFGH',
|
||||
exampleDisplayName: 'Kitchen',
|
||||
},
|
||||
];
|
||||
|
||||
// loop over the discovered devices and register each one if it has not already been registered
|
||||
for (const device of exampleDevices) {
|
||||
|
||||
// generate a unique id for the accessory this should be generated from
|
||||
// something globally unique, but constant, for example, the device serial
|
||||
// number or MAC address
|
||||
const uuid = this.api.hap.uuid.generate(device.exampleUniqueId);
|
||||
|
||||
// see if an accessory with the same uuid has already been registered and restored from
|
||||
// the cached devices we stored in the `configureAccessory` method above
|
||||
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
||||
|
||||
if (existingAccessory) {
|
||||
// the accessory already exists
|
||||
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
|
||||
|
||||
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
||||
// existingAccessory.context.device = device;
|
||||
// this.api.updatePlatformAccessories([existingAccessory]);
|
||||
|
||||
// create the accessory handler for the restored accessory
|
||||
// this is imported from `platformAccessory.ts`
|
||||
new ExamplePlatformAccessory(this, existingAccessory);
|
||||
|
||||
// it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.:
|
||||
// remove platform accessories when no longer present
|
||||
// this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
|
||||
// this.log.info('Removing existing accessory from cache:', existingAccessory.displayName);
|
||||
} else {
|
||||
// the accessory does not yet exist, so we need to create it
|
||||
this.log.info('Adding new accessory:', device.exampleDisplayName);
|
||||
|
||||
// create a new accessory
|
||||
const accessory = new this.api.platformAccessory(device.exampleDisplayName, uuid);
|
||||
|
||||
// store a copy of the device object in the `accessory.context`
|
||||
// the `context` property can be used to store any data about the accessory you may need
|
||||
accessory.context.device = device;
|
||||
|
||||
// create the accessory handler for the newly create accessory
|
||||
// this is imported from `platformAccessory.ts`
|
||||
new ExamplePlatformAccessory(this, accessory);
|
||||
|
||||
// link the accessory to your platform
|
||||
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
||||
}
|
||||
this.api.on('didFinishLaunching', () => {
|
||||
this.log.debug('Finished launching %s', this.config.platform)
|
||||
this.startHapDiscovery()
|
||||
})
|
||||
}
|
||||
|
||||
private configure(): void {
|
||||
if (this.config.pin !== 'string' || !this.config.pin.match(/^\d{3}-\d{2}-\d{3}$/)) {
|
||||
this.log.error('"pin" must be defined in config and match format 000-00-000')
|
||||
}
|
||||
|
||||
this.config.debug = this.config.debug ?? false
|
||||
this.config.probe_port = this.config.probe_port ?? 36123
|
||||
this.config.refresh_interval = this.config.refresh_interval || 60
|
||||
this.config.request_timeout = this.config.request_timeout || 10
|
||||
this.config.discovery_timeout = this.config.discovery_timeout || 20
|
||||
|
||||
this.log.debug('Configuration materialized: %o', this.config)
|
||||
}
|
||||
|
||||
private startHttpServer(): void {
|
||||
this.log.debug('Starting probe HTTP server on port %d', this.config.probe_port)
|
||||
|
||||
const contentTypeHeader = { 'Content-Type': 'text/plain; charset=UTF-8' }
|
||||
serve({
|
||||
port: this.config.probe_port,
|
||||
logger: this.log,
|
||||
requestInterceptor: () => {
|
||||
if (!this.metricsDiscovered) {
|
||||
return {
|
||||
statusCode: 503,
|
||||
headers: { ...contentTypeHeader, 'Retry-After': '10' },
|
||||
body: 'Discovery pending',
|
||||
}
|
||||
}
|
||||
},
|
||||
probeController: () => {
|
||||
const prefix = 'homebridge_'
|
||||
const metrics = this.metrics
|
||||
.map((metric) => [
|
||||
`# TYPE ${prefix}${metric.name} gauge`,
|
||||
`${prefix}${metric.name}{${Object.entries(metric.labels)
|
||||
.map(([key, value]) => `${key}="${value}"`)
|
||||
.join(',')}} ${metric.value}`,
|
||||
])
|
||||
.flat()
|
||||
.join('\n')
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: contentTypeHeader,
|
||||
body: metrics,
|
||||
}
|
||||
},
|
||||
notFoundController: () => ({
|
||||
statusCode: 404,
|
||||
headers: contentTypeHeader,
|
||||
body: 'Not found. Try /probe',
|
||||
}),
|
||||
errorController: () => ({
|
||||
statusCode: 500,
|
||||
headers: contentTypeHeader,
|
||||
body: 'Server error',
|
||||
}),
|
||||
})
|
||||
.then((http) => {
|
||||
this.log.debug('HTTP server started on port %d', this.config.probe_port)
|
||||
this.http = http
|
||||
})
|
||||
.catch((e) => {
|
||||
this.log.error('Failed to start probe HTTP server on port %d: %o', this.config.probe_port, e)
|
||||
})
|
||||
}
|
||||
|
||||
private startHapDiscovery(): void {
|
||||
this.log.debug('Starting HAP discovery')
|
||||
discover({
|
||||
logger: this.log,
|
||||
refreshInterval: this.config.refresh_interval,
|
||||
discoveryTimeout: this.config.discovery_timeout,
|
||||
requestTimeout: this.config.request_timeout,
|
||||
pin: this.config.pin,
|
||||
debug: this.config.debug,
|
||||
})
|
||||
.then((devices) => {
|
||||
this.metrics = aggregate(devices)
|
||||
this.metricsDiscovered = true
|
||||
this.log.debug('HAP discovery completed, %d metrics discovered', this.metrics.length)
|
||||
})
|
||||
.catch((e) => {
|
||||
this.log.error('HAP discovery error', e)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
||||
|
||||
import { ExampleHomebridgePlatform } from './platform';
|
||||
|
||||
/**
|
||||
* Platform Accessory
|
||||
* An instance of this class is created for each accessory your platform registers
|
||||
* Each accessory may expose multiple services of different service types.
|
||||
*/
|
||||
export class ExamplePlatformAccessory {
|
||||
private service: Service;
|
||||
|
||||
/**
|
||||
* These are just used to create a working example
|
||||
* You should implement your own code to track the state of your accessory
|
||||
*/
|
||||
private exampleStates = {
|
||||
On: false,
|
||||
Brightness: 100,
|
||||
};
|
||||
|
||||
constructor(
|
||||
private readonly platform: ExampleHomebridgePlatform,
|
||||
private readonly accessory: PlatformAccessory,
|
||||
) {
|
||||
|
||||
// set accessory information
|
||||
this.accessory.getService(this.platform.Service.AccessoryInformation)!
|
||||
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Default-Manufacturer')
|
||||
.setCharacteristic(this.platform.Characteristic.Model, 'Default-Model')
|
||||
.setCharacteristic(this.platform.Characteristic.SerialNumber, 'Default-Serial');
|
||||
|
||||
// get the LightBulb service if it exists, otherwise create a new LightBulb service
|
||||
// you can create multiple services for each accessory
|
||||
this.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb);
|
||||
|
||||
// set the service name, this is what is displayed as the default name on the Home app
|
||||
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
|
||||
this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.exampleDisplayName);
|
||||
|
||||
// each service must implement at-minimum the "required characteristics" for the given service type
|
||||
// see https://developers.homebridge.io/#/service/Lightbulb
|
||||
|
||||
// register handlers for the On/Off Characteristic
|
||||
this.service.getCharacteristic(this.platform.Characteristic.On)
|
||||
.onSet(this.setOn.bind(this)) // SET - bind to the `setOn` method below
|
||||
.onGet(this.getOn.bind(this)); // GET - bind to the `getOn` method below
|
||||
|
||||
// register handlers for the Brightness Characteristic
|
||||
this.service.getCharacteristic(this.platform.Characteristic.Brightness)
|
||||
.onSet(this.setBrightness.bind(this)); // SET - bind to the 'setBrightness` method below
|
||||
|
||||
/**
|
||||
* Creating multiple services of the same type.
|
||||
*
|
||||
* To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
|
||||
* when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
|
||||
* this.accessory.getService('NAME') || this.accessory.addService(this.platform.Service.Lightbulb, 'NAME', 'USER_DEFINED_SUBTYPE_ID');
|
||||
*
|
||||
* The USER_DEFINED_SUBTYPE must be unique to the platform accessory (if you platform exposes multiple accessories, each accessory
|
||||
* can use the same sub type id.)
|
||||
*/
|
||||
|
||||
// Example: add two "motion sensor" services to the accessory
|
||||
const motionSensorOneService = this.accessory.getService('Motion Sensor One Name') ||
|
||||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor One Name', 'YourUniqueIdentifier-1');
|
||||
|
||||
const motionSensorTwoService = this.accessory.getService('Motion Sensor Two Name') ||
|
||||
this.accessory.addService(this.platform.Service.MotionSensor, 'Motion Sensor Two Name', 'YourUniqueIdentifier-2');
|
||||
|
||||
/**
|
||||
* Updating characteristics values asynchronously.
|
||||
*
|
||||
* Example showing how to update the state of a Characteristic asynchronously instead
|
||||
* of using the `on('get')` handlers.
|
||||
* Here we change update the motion sensor trigger states on and off every 10 seconds
|
||||
* the `updateCharacteristic` method.
|
||||
*
|
||||
*/
|
||||
let motionDetected = false;
|
||||
setInterval(() => {
|
||||
// EXAMPLE - inverse the trigger
|
||||
motionDetected = !motionDetected;
|
||||
|
||||
// push the new value to HomeKit
|
||||
motionSensorOneService.updateCharacteristic(this.platform.Characteristic.MotionDetected, motionDetected);
|
||||
motionSensorTwoService.updateCharacteristic(this.platform.Characteristic.MotionDetected, !motionDetected);
|
||||
|
||||
this.platform.log.debug('Triggering motionSensorOneService:', motionDetected);
|
||||
this.platform.log.debug('Triggering motionSensorTwoService:', !motionDetected);
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "SET" requests from HomeKit
|
||||
* These are sent when the user changes the state of an accessory, for example, turning on a Light bulb.
|
||||
*/
|
||||
async setOn(value: CharacteristicValue) {
|
||||
// implement your own code to turn your device on/off
|
||||
this.exampleStates.On = value as boolean;
|
||||
|
||||
this.platform.log.debug('Set Characteristic On ->', value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the "GET" requests from HomeKit
|
||||
* These are sent when HomeKit wants to know the current state of the accessory, for example, checking if a Light bulb is on.
|
||||
*
|
||||
* GET requests should return as fast as possbile. A long delay here will result in
|
||||
* HomeKit being unresponsive and a bad user experience in general.
|
||||
*
|
||||
* If your device takes time to respond you should update the status of your device
|
||||
* asynchronously instead using the `updateCharacteristic` method instead.
|
||||
|
||||
* @example
|
||||
* this.service.updateCharacteristic(this.platform.Characteristic.On, true)
|
||||
*/
|
||||
async getOn(): Promise<CharacteristicValue> {
|
||||
// implement your own code to check if the device is on
|
||||
const isOn = this.exampleStates.On;
|
||||
|
||||
this.platform.log.debug('Get Characteristic On ->', isOn);
|
||||
|
||||
// if you need to return an error to show the device as "Not Responding" in the Home app:
|
||||
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||
|
||||
return isOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "SET" requests from HomeKit
|
||||
* These are sent when the user changes the state of an accessory, for example, changing the Brightness
|
||||
*/
|
||||
async setBrightness(value: CharacteristicValue) {
|
||||
// implement your own code to set the brightness
|
||||
this.exampleStates.Brightness = value as number;
|
||||
|
||||
this.platform.log.debug('Set Characteristic Brightness -> ', value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,2 @@
|
|||
/**
|
||||
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
||||
*/
|
||||
export const PLATFORM_NAME = 'ExampleHomebridgePlugin';
|
||||
|
||||
/**
|
||||
* This must match the name of your plugin as defined the package.json
|
||||
*/
|
||||
export const PLUGIN_NAME = 'homebridge-plugin-name';
|
||||
export const PLATFORM_NAME = 'PrometheusExporter'
|
||||
export const PLUGIN_NAME = 'homebridge-prometheus-exporter'
|
||||
|
|
11
src/std.ts
Normal file
11
src/std.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
type Types = 'string' | 'number' | 'boolean' | 'object'
|
||||
type TypeMap = {
|
||||
string: string
|
||||
number: number
|
||||
boolean: boolean
|
||||
object: object
|
||||
}
|
||||
|
||||
export function isType<T extends Types>(type: T): (v: unknown) => v is TypeMap[T] {
|
||||
return (v: unknown): v is TypeMap[T] => typeof v === type
|
||||
}
|
156
tests/aggregator.test.ts
Normal file
156
tests/aggregator.test.ts
Normal file
|
@ -0,0 +1,156 @@
|
|||
import { describe, expect, test } from '@jest/globals'
|
||||
import { DeviceBoundary } from '../src/boundaries'
|
||||
import { Metric, aggregate } from '../src/metrics'
|
||||
import dysonData from './fixtures/dyson.json'
|
||||
import emptyData from './fixtures/empty.json'
|
||||
import tpLinkData from './fixtures/tp-link.json'
|
||||
import harmonyData from './fixtures/harmony.json'
|
||||
|
||||
describe('Metrics aggregator', () => {
|
||||
test('Aggregates homebridge-dyson fan metrics', () => {
|
||||
const dyson = DeviceBoundary.check(dysonData)
|
||||
|
||||
const expectedLabels = {
|
||||
bridge: 'Dyson bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
firmware_revision: '21.04.03',
|
||||
hardware_revision: 'TP02',
|
||||
manufacturer: 'Dyson',
|
||||
model: 'Dyson Pure Cool Link Tower',
|
||||
name: 'Office',
|
||||
serial_number: 'NN2-EU-KKA0717A',
|
||||
}
|
||||
|
||||
expect(aggregate([dyson])).toEqual([
|
||||
new Metric('air_purifier_active', 0, 'uint8', expectedLabels),
|
||||
new Metric('air_purifier_current_air_purifier_state', 0, 'uint8', expectedLabels),
|
||||
new Metric('air_purifier_target_air_purifier_state', 0, 'uint8', expectedLabels),
|
||||
new Metric('air_purifier_filter_life_level_percentage', 85, 'float', expectedLabels),
|
||||
new Metric('air_purifier_rotation_speed_percentage', 100, 'float', expectedLabels),
|
||||
new Metric('air_purifier_current_temperature_celsius', 22.8, 'float', expectedLabels),
|
||||
new Metric('air_purifier_swing_mode', 0, 'uint8', expectedLabels),
|
||||
new Metric('air_purifier_filter_change_indication', 0, 'uint8', expectedLabels),
|
||||
new Metric('air_purifier_current_relative_humidity_percentage', 52, 'float', expectedLabels),
|
||||
new Metric('air_purifier_air_quality', 2, 'uint8', expectedLabels),
|
||||
])
|
||||
})
|
||||
|
||||
test('Aggregates empty accessory metrics to empty metrics', () => {
|
||||
const empty = DeviceBoundary.check(emptyData)
|
||||
|
||||
expect(aggregate([empty])).toEqual([])
|
||||
})
|
||||
|
||||
test('Aggregates TP-Link plugs metrics', () => {
|
||||
const tpLink = DeviceBoundary.check(tpLinkData)
|
||||
|
||||
const expectedLabelsAccessory1 = {
|
||||
bridge: 'TP-Link bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
firmware_revision: '1.5.6 Build 191125 Rel.083657',
|
||||
hardware_revision: '2.0',
|
||||
manufacturer: 'TP-Link',
|
||||
model: 'HS110(EU)',
|
||||
name: 'Drucker',
|
||||
serial_number: 'AA:AA:AA:AA:AA:AA 8006106A8B451F91FA0498A6615963E019CCD80A',
|
||||
}
|
||||
|
||||
const expectedLabelsAccessory2 = {
|
||||
bridge: 'TP-Link bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
firmware_revision: '1.5.6 Build 191125 Rel.083657',
|
||||
hardware_revision: '2.0',
|
||||
manufacturer: 'TP-Link',
|
||||
model: 'HS110(EU)',
|
||||
name: 'Espressomaschine',
|
||||
serial_number: 'AA:AA:AA:AA:AA:AA 800614AA26608873C919E4592765404019F64D07',
|
||||
}
|
||||
|
||||
expect(aggregate([tpLink])).toEqual([
|
||||
new Metric('outlet_amperes_a', 0.03, 'float', expectedLabelsAccessory1),
|
||||
new Metric('outlet_total_consumption_kwh', 0.051, 'float', expectedLabelsAccessory1),
|
||||
new Metric('outlet_apparent_power_va', 53248.8, 'float', expectedLabelsAccessory1),
|
||||
new Metric('outlet_volts_v', 230.8, 'float', expectedLabelsAccessory1),
|
||||
new Metric('outlet_consumption_w', 0, 'float', expectedLabelsAccessory1),
|
||||
new Metric('outlet_amperes_a', 0.03, 'float', expectedLabelsAccessory2),
|
||||
new Metric('outlet_total_consumption_kwh', 13.025, 'float', expectedLabelsAccessory2),
|
||||
new Metric('outlet_apparent_power_va', 53365.6, 'float', expectedLabelsAccessory2),
|
||||
new Metric('outlet_volts_v', 231, 'float', expectedLabelsAccessory2),
|
||||
new Metric('outlet_consumption_w', 0, 'float', expectedLabelsAccessory2),
|
||||
])
|
||||
})
|
||||
|
||||
test('Aggregates homebridge-harmony remote metrics', () => {
|
||||
const harmony = DeviceBoundary.check(harmonyData)
|
||||
|
||||
const expectedLabels1 = {
|
||||
bridge: 'Harmony bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
configured_name: 'Fernbedienung',
|
||||
firmware_revision: '1.6.2',
|
||||
manufacturer: 'Logitech',
|
||||
model: 'Fernbedienung Wohnzimmer',
|
||||
name: 'Fernbedienung Wohnzimmer',
|
||||
serial_number: '0e88f449-2720-4000-8c4b-06775986e8ac',
|
||||
}
|
||||
|
||||
const expectedLabels2 = {
|
||||
bridge: 'Harmony bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
configured_name: 'CD',
|
||||
firmware_revision: '1.6.2',
|
||||
manufacturer: 'Logitech',
|
||||
model: 'Fernbedienung Wohnzimmer',
|
||||
name: 'CD',
|
||||
serial_number: '0e88f449-2720-4000-8c4b-06775986e8ac',
|
||||
}
|
||||
|
||||
const expectedLabels3 = {
|
||||
bridge: 'Harmony bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
configured_name: 'AirPlay',
|
||||
firmware_revision: '1.6.2',
|
||||
manufacturer: 'Logitech',
|
||||
model: 'Fernbedienung Wohnzimmer',
|
||||
name: 'AirPlay',
|
||||
serial_number: '0e88f449-2720-4000-8c4b-06775986e8ac',
|
||||
}
|
||||
|
||||
const expectedLabels4 = {
|
||||
bridge: 'Harmony bridge',
|
||||
device_id: 'AA:AA:AA:AA:AA:AA',
|
||||
instance: 'http://192.168.0.1:38333',
|
||||
firmware_revision: '1.6.2',
|
||||
manufacturer: 'Logitech',
|
||||
model: 'Fernbedienung Wohnzimmer',
|
||||
name: 'Fernbedienung Wohnzimmer',
|
||||
serial_number: '0e88f449-2720-4000-8c4b-06775986e8ac',
|
||||
}
|
||||
|
||||
expect(aggregate([harmony])).toEqual([
|
||||
new Metric('television_sleep_discovery_mode', 1, 'uint8', expectedLabels1),
|
||||
new Metric('television_active', 0, 'uint8', expectedLabels1),
|
||||
new Metric('television_active_identifier', 0, 'uint32', expectedLabels1),
|
||||
|
||||
new Metric('input_source_type', 10, 'uint8', expectedLabels2),
|
||||
new Metric('input_source_is_configured', 1, 'uint8', expectedLabels2),
|
||||
new Metric('input_source_current_visibility_state', 0, 'uint8', expectedLabels2),
|
||||
new Metric('input_source_target_visibility_state', 0, 'uint8', expectedLabels2),
|
||||
|
||||
new Metric('input_source_type', 10, 'uint8', expectedLabels3),
|
||||
new Metric('input_source_is_configured', 1, 'uint8', expectedLabels3),
|
||||
new Metric('input_source_current_visibility_state', 0, 'uint8', expectedLabels3),
|
||||
new Metric('input_source_target_visibility_state', 0, 'uint8', expectedLabels3),
|
||||
|
||||
new Metric('speaker_active', 1, 'uint8', expectedLabels4),
|
||||
new Metric('speaker_volume_control_type', 3, 'uint8', expectedLabels4),
|
||||
new Metric('speaker_volume_percentage', 50, 'uint8', expectedLabels4),
|
||||
])
|
||||
})
|
||||
})
|
300
tests/fixtures/dyson.json
vendored
Normal file
300
tests/fixtures/dyson.json
vendored
Normal file
|
@ -0,0 +1,300 @@
|
|||
{
|
||||
"ipAddress": "192.168.0.1",
|
||||
"instance": {
|
||||
"host": "192.168.0.1",
|
||||
"port": 38333,
|
||||
"url": "http://192.168.0.1:38333",
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"txt": {
|
||||
"c#": "5",
|
||||
"ff": "0",
|
||||
"id": "AA:AA:AA:AA:AA:AA",
|
||||
"md": "homebridge",
|
||||
"pv": "1.1",
|
||||
"s#": "1",
|
||||
"sf": "0",
|
||||
"ci": "2",
|
||||
"sh": "VOLG3g=="
|
||||
},
|
||||
"name": "Dyson bridge"
|
||||
},
|
||||
"accessories": {
|
||||
"accessories": [
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "homebridge.io",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "homebridge",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Dyson Ventilator Bridge 2437",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "AA:AA:AA:AA:AA:AA",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.5.1",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000A2-0000-1000-8000-0026BB765291",
|
||||
"iid": 2000000008,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000037-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"value": "1.1.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Version",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 2,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "Dyson",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "Dyson Pure Cool Link Tower",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Office",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "NN2-EU-KKA0717A",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "21.04.03",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "00000053-0000-1000-8000-0026BB765291",
|
||||
"iid": 8,
|
||||
"value": "TP02",
|
||||
"perms": ["pr"],
|
||||
"description": "Hardware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000BB-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "000000B0-0000-1000-8000-0026BB765291",
|
||||
"iid": 10,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Active",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000A9-0000-1000-8000-0026BB765291",
|
||||
"iid": 11,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Current Air Purifier State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 2,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2]
|
||||
},
|
||||
{
|
||||
"type": "000000A8-0000-1000-8000-0026BB765291",
|
||||
"iid": 12,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Target Air Purifier State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000AB-0000-1000-8000-0026BB765291",
|
||||
"iid": 13,
|
||||
"value": 85,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Filter Life Level",
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"minStep": 1
|
||||
},
|
||||
{
|
||||
"type": "00000029-0000-1000-8000-0026BB765291",
|
||||
"iid": 14,
|
||||
"value": 100,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Rotation Speed",
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"minStep": 10
|
||||
},
|
||||
{
|
||||
"type": "00000011-0000-1000-8000-0026BB765291",
|
||||
"iid": 15,
|
||||
"value": 22.8,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Current Temperature",
|
||||
"format": "float",
|
||||
"unit": "celsius",
|
||||
"minValue": -50,
|
||||
"maxValue": 100,
|
||||
"minStep": 0.1
|
||||
},
|
||||
{
|
||||
"type": "000000B6-0000-1000-8000-0026BB765291",
|
||||
"iid": 16,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Swing Mode",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000AC-0000-1000-8000-0026BB765291",
|
||||
"iid": 17,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Filter Change Indication",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "00000010-0000-1000-8000-0026BB765291",
|
||||
"iid": 18,
|
||||
"value": 52,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Current Relative Humidity",
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"minStep": 1
|
||||
},
|
||||
{
|
||||
"type": "00000095-0000-1000-8000-0026BB765291",
|
||||
"iid": 19,
|
||||
"value": 2,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Air Quality",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 5,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2, 3, 4, 5]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"name": "homebridge"
|
||||
}
|
104
tests/fixtures/empty.json
vendored
Normal file
104
tests/fixtures/empty.json
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"ipAddress": "192.168.0.1",
|
||||
"instance": {
|
||||
"host": "192.168.0.1",
|
||||
"port": 51826,
|
||||
"url": "http://192.168.0.1:51826",
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"txt": {
|
||||
"c#": "5",
|
||||
"ff": "0",
|
||||
"id": "AA:AA:AA:AA:AA:AA",
|
||||
"md": "homebridge",
|
||||
"pv": "1.1",
|
||||
"s#": "1",
|
||||
"sf": "0",
|
||||
"ci": "2",
|
||||
"sh": "Hv0v9A=="
|
||||
},
|
||||
"name": "Empty bridge"
|
||||
},
|
||||
"accessories": {
|
||||
"accessories": [
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "homebridge.io",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "homebridge",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Homebridge D2FB",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "AA:AA:AA:AA:AA:AA",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.5.1",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000A2-0000-1000-8000-0026BB765291",
|
||||
"iid": 2000000008,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000037-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"value": "1.1.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Version",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"name": "homebridge"
|
||||
}
|
410
tests/fixtures/harmony.json
vendored
Normal file
410
tests/fixtures/harmony.json
vendored
Normal file
|
@ -0,0 +1,410 @@
|
|||
{
|
||||
"ipAddress": "192.168.0.1",
|
||||
"instance": {
|
||||
"host": "192.168.0.1",
|
||||
"port": 38333,
|
||||
"url": "http://192.168.0.1:38333",
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"txt": {
|
||||
"c#": "2",
|
||||
"ff": "0",
|
||||
"id": "AA:AA:AA:AA:AA:AA",
|
||||
"md": "Fernbedienung Wohnzimmer",
|
||||
"pv": "1.1",
|
||||
"s#": "1",
|
||||
"sf": "0",
|
||||
"ci": "31",
|
||||
"sh": "Aa6YjQ=="
|
||||
},
|
||||
"name": "Harmony bridge"
|
||||
},
|
||||
"accessories": {
|
||||
"accessories": [
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "Logitech",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "Fernbedienung Wohnzimmer",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Fernbedienung Wohnzimmer-TV 970C",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "0e88f449-2720-4000-8c4b-06775986e8ac",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.6.2",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000D8-0000-1000-8000-0026BB765291",
|
||||
"iid": 8,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "000000E1-0000-1000-8000-0026BB765291",
|
||||
"iid": 13,
|
||||
"perms": ["pw"],
|
||||
"description": "Remote Key",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 16,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
|
||||
},
|
||||
{
|
||||
"type": "000000DF-0000-1000-8000-0026BB765291",
|
||||
"iid": 15,
|
||||
"perms": ["pw"],
|
||||
"description": "Power Mode Selection",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"value": "Fernbedienung Wohnzimmer",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "000000E3-0000-1000-8000-0026BB765291",
|
||||
"iid": 12,
|
||||
"value": "Fernbedienung",
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Configured Name",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "000000E8-0000-1000-8000-0026BB765291",
|
||||
"iid": 14,
|
||||
"value": 1,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Sleep Discovery Mode",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000B0-0000-1000-8000-0026BB765291",
|
||||
"iid": 10,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Active",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000E7-0000-1000-8000-0026BB765291",
|
||||
"iid": 11,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Active Identifier",
|
||||
"format": "uint32"
|
||||
}
|
||||
],
|
||||
"linked": [16, 24, 32]
|
||||
},
|
||||
{
|
||||
"type": "000000D9-0000-1000-8000-0026BB765291",
|
||||
"iid": 16,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 17,
|
||||
"value": "CD",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "000000E3-0000-1000-8000-0026BB765291",
|
||||
"iid": 18,
|
||||
"value": "CD",
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Configured Name",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "000000DB-0000-1000-8000-0026BB765291",
|
||||
"iid": 19,
|
||||
"value": 10,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Input Source Type",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 10,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
},
|
||||
{
|
||||
"type": "000000D6-0000-1000-8000-0026BB765291",
|
||||
"iid": 20,
|
||||
"value": 1,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Is Configured",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000E6-0000-1000-8000-0026BB765291",
|
||||
"iid": 22,
|
||||
"value": 1,
|
||||
"perms": ["pr"],
|
||||
"description": "Identifier",
|
||||
"format": "uint32"
|
||||
},
|
||||
{
|
||||
"type": "00000135-0000-1000-8000-0026BB765291",
|
||||
"iid": 21,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Current Visibility State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "00000134-0000-1000-8000-0026BB765291",
|
||||
"iid": 23,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Target Visibility State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000D9-0000-1000-8000-0026BB765291",
|
||||
"iid": 24,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 25,
|
||||
"value": "AirPlay",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "000000E3-0000-1000-8000-0026BB765291",
|
||||
"iid": 26,
|
||||
"value": "AirPlay",
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Configured Name",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "000000DB-0000-1000-8000-0026BB765291",
|
||||
"iid": 27,
|
||||
"value": 10,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Input Source Type",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 10,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
},
|
||||
{
|
||||
"type": "000000D6-0000-1000-8000-0026BB765291",
|
||||
"iid": 28,
|
||||
"value": 1,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Is Configured",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000E6-0000-1000-8000-0026BB765291",
|
||||
"iid": 30,
|
||||
"value": 2,
|
||||
"perms": ["pr"],
|
||||
"description": "Identifier",
|
||||
"format": "uint32"
|
||||
},
|
||||
{
|
||||
"type": "00000135-0000-1000-8000-0026BB765291",
|
||||
"iid": 29,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Current Visibility State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "00000134-0000-1000-8000-0026BB765291",
|
||||
"iid": 31,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Target Visibility State",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "00000113-0000-1000-8000-0026BB765291",
|
||||
"iid": 32,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "000000EA-0000-1000-8000-0026BB765291",
|
||||
"iid": 37,
|
||||
"perms": ["pw"],
|
||||
"description": "Volume Selector",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 33,
|
||||
"value": "Fernbedienung Wohnzimmer",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "000000B0-0000-1000-8000-0026BB765291",
|
||||
"iid": 35,
|
||||
"value": 1,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Active",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 1,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1]
|
||||
},
|
||||
{
|
||||
"type": "000000E9-0000-1000-8000-0026BB765291",
|
||||
"iid": 36,
|
||||
"value": 3,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Volume Control Type",
|
||||
"format": "uint8",
|
||||
"minValue": 0,
|
||||
"maxValue": 3,
|
||||
"minStep": 1,
|
||||
"valid-values": [0, 1, 2, 3]
|
||||
},
|
||||
{
|
||||
"type": "0000011A-0000-1000-8000-0026BB765291",
|
||||
"iid": 34,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Mute",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000119-0000-1000-8000-0026BB765291",
|
||||
"iid": 38,
|
||||
"value": 50,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "Volume",
|
||||
"format": "uint8",
|
||||
"unit": "percentage",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"minStep": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000A2-0000-1000-8000-0026BB765291",
|
||||
"iid": 39,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000037-0000-1000-8000-0026BB765291",
|
||||
"iid": 40,
|
||||
"value": "1.1.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Version",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"name": "Fernbedienung Wohnzimmer"
|
||||
}
|
426
tests/fixtures/tp-link.json
vendored
Normal file
426
tests/fixtures/tp-link.json
vendored
Normal file
|
@ -0,0 +1,426 @@
|
|||
{
|
||||
"ipAddress": "192.168.0.1",
|
||||
"instance": {
|
||||
"host": "192.168.0.1",
|
||||
"port": 38333,
|
||||
"url": "http://192.168.0.1:38333",
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"txt": {
|
||||
"c#": "3",
|
||||
"ff": "0",
|
||||
"id": "AA:AA:AA:AA:AA:AA",
|
||||
"md": "homebridge",
|
||||
"pv": "1.1",
|
||||
"s#": "1",
|
||||
"sf": "0",
|
||||
"ci": "2",
|
||||
"sh": "RovnEA=="
|
||||
},
|
||||
"name": "TP-Link bridge"
|
||||
},
|
||||
"accessories": {
|
||||
"accessories": [
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "homebridge.io",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "homebridge",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "TP-Link Steckdosen Bridge 8EB6",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "AA:AA:AA:AA:AA:AA",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.5.1",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "000000A2-0000-1000-8000-0026BB765291",
|
||||
"iid": 2000000008,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000037-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"value": "1.1.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Version",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 2,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "TP-Link",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "HS110(EU)",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Drucker",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "AA:AA:AA:AA:AA:AA 8006106A8B451F91FA0498A6615963E019CCD80A",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.5.6 Build 191125 Rel.083657",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "00000053-0000-1000-8000-0026BB765291",
|
||||
"iid": 8,
|
||||
"value": "2.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Hardware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "00000047-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 10,
|
||||
"value": "Drucker",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000025-0000-1000-8000-0026BB765291",
|
||||
"iid": 11,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "On",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000026-0000-1000-8000-0026BB765291",
|
||||
"iid": 12,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Outlet In Use",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "E863F126-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 13,
|
||||
"value": 0.03,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Amperes",
|
||||
"format": "float",
|
||||
"unit": "A",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.01
|
||||
},
|
||||
{
|
||||
"type": "E863F10C-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 14,
|
||||
"value": 0.051,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Total Consumption",
|
||||
"format": "float",
|
||||
"unit": "kWh",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.001
|
||||
},
|
||||
{
|
||||
"type": "E863F110-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 15,
|
||||
"value": 53248.8,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Apparent Power",
|
||||
"format": "float",
|
||||
"unit": "VA",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
},
|
||||
{
|
||||
"type": "E863F10A-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 16,
|
||||
"value": 230.8,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Volts",
|
||||
"format": "float",
|
||||
"unit": "V",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
},
|
||||
{
|
||||
"type": "E863F10D-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 17,
|
||||
"value": 0,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Consumption",
|
||||
"format": "float",
|
||||
"unit": "W",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 3,
|
||||
"services": [
|
||||
{
|
||||
"type": "0000003E-0000-1000-8000-0026BB765291",
|
||||
"iid": 1,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000014-0000-1000-8000-0026BB765291",
|
||||
"iid": 2,
|
||||
"perms": ["pw"],
|
||||
"description": "Identify",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000020-0000-1000-8000-0026BB765291",
|
||||
"iid": 3,
|
||||
"value": "TP-Link",
|
||||
"perms": ["pr"],
|
||||
"description": "Manufacturer",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000021-0000-1000-8000-0026BB765291",
|
||||
"iid": 4,
|
||||
"value": "HS110(EU)",
|
||||
"perms": ["pr"],
|
||||
"description": "Model",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 5,
|
||||
"value": "Espressomaschine",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000030-0000-1000-8000-0026BB765291",
|
||||
"iid": 6,
|
||||
"value": "AA:AA:AA:AA:AA:AA 800614AA26608873C919E4592765404019F64D07",
|
||||
"perms": ["pr"],
|
||||
"description": "Serial Number",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000052-0000-1000-8000-0026BB765291",
|
||||
"iid": 7,
|
||||
"value": "1.5.6 Build 191125 Rel.083657",
|
||||
"perms": ["pr"],
|
||||
"description": "Firmware Revision",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"type": "00000053-0000-1000-8000-0026BB765291",
|
||||
"iid": 8,
|
||||
"value": "2.0",
|
||||
"perms": ["pr"],
|
||||
"description": "Hardware Revision",
|
||||
"format": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "00000047-0000-1000-8000-0026BB765291",
|
||||
"iid": 9,
|
||||
"characteristics": [
|
||||
{
|
||||
"type": "00000023-0000-1000-8000-0026BB765291",
|
||||
"iid": 10,
|
||||
"value": "Espressomaschine",
|
||||
"perms": ["pr"],
|
||||
"description": "Name",
|
||||
"format": "string",
|
||||
"maxLen": 64
|
||||
},
|
||||
{
|
||||
"type": "00000025-0000-1000-8000-0026BB765291",
|
||||
"iid": 11,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr", "pw"],
|
||||
"description": "On",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "00000026-0000-1000-8000-0026BB765291",
|
||||
"iid": 12,
|
||||
"value": 0,
|
||||
"perms": ["ev", "pr"],
|
||||
"description": "Outlet In Use",
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"type": "E863F126-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 13,
|
||||
"value": 0.03,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Amperes",
|
||||
"format": "float",
|
||||
"unit": "A",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.01
|
||||
},
|
||||
{
|
||||
"type": "E863F10C-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 14,
|
||||
"value": 13.025,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Total Consumption",
|
||||
"format": "float",
|
||||
"unit": "kWh",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.001
|
||||
},
|
||||
{
|
||||
"type": "E863F110-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 15,
|
||||
"value": 53365.6,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Apparent Power",
|
||||
"format": "float",
|
||||
"unit": "VA",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
},
|
||||
{
|
||||
"type": "E863F10A-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 16,
|
||||
"value": 231,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Volts",
|
||||
"format": "float",
|
||||
"unit": "V",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
},
|
||||
{
|
||||
"type": "E863F10D-079E-48FF-8F27-9C2605A29F52",
|
||||
"iid": 17,
|
||||
"value": 0,
|
||||
"perms": ["pr", "ev"],
|
||||
"description": "Consumption",
|
||||
"format": "float",
|
||||
"unit": "W",
|
||||
"minValue": 0,
|
||||
"maxValue": 65535,
|
||||
"minStep": 0.1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"deviceID": "AA:AA:AA:AA:AA:AA",
|
||||
"name": "homebridge"
|
||||
}
|
18
tests/formatter.test.ts
Normal file
18
tests/formatter.test.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { describe, expect, test } from '@jest/globals'
|
||||
import { formatName } from '../src/metrics'
|
||||
|
||||
describe('Metrics formatter', () => {
|
||||
test('Converts to snake case', () => {
|
||||
expect(formatName('Service', 'Metric')).toEqual('service_metric')
|
||||
})
|
||||
test('Handles camel case', () => {
|
||||
expect(formatName('YetAnotherService', 'Some Metric')).toEqual('yet_another_service_some_metric')
|
||||
})
|
||||
|
||||
test('Strips duplicate prefixes', () => {
|
||||
expect(formatName('Some Service', 'Some Service Metric')).toEqual('some_service_metric')
|
||||
expect(formatName('Some Service', 'SomeServiceMetric')).toEqual('some_service_metric')
|
||||
expect(formatName('SomeService', 'SomeServiceMetric')).toEqual('some_service_metric')
|
||||
expect(formatName('SomeService', 'Some Service Metric')).toEqual('some_service_metric')
|
||||
})
|
||||
})
|
|
@ -1,26 +1,18 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2018", // ~node10
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es2015",
|
||||
"es2016",
|
||||
"es2017",
|
||||
"es2018"
|
||||
],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": [
|
||||
"src/"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
"compilerOptions": {
|
||||
"target": "ES2021",
|
||||
"module": "commonjs",
|
||||
"lib": ["es2015", "es2016", "es2017", "es2018"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"noImplicitAny": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/"],
|
||||
"exclude": ["**/*.test.ts", "node_modules/hap-nodejs/**/**"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue