Skip to content

Commit

Permalink
feat(config): add config validation (#555)
Browse files Browse the repository at this point in the history
  • Loading branch information
PeteBa committed Mar 10, 2021
1 parent acb0e1a commit 7acc37f
Show file tree
Hide file tree
Showing 22 changed files with 1,083 additions and 78 deletions.
60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -61,6 +61,7 @@
"config": "^3.3.3",
"democracy": "^3.1.3",
"github-sponsors": "^1.0.1",
"joiful": "^3.0.0",
"js-yaml": "^3.14.1",
"kalmanjs": "^1.1.0",
"lodash": "^4.17.21",
Expand Down
43 changes: 43 additions & 0 deletions src/app.config.ts
@@ -0,0 +1,43 @@
import { BluetoothLowEnergyConfig } from './integrations/bluetooth-low-energy/bluetooth-low-energy.config';
import { ClusterConfig } from './cluster/cluster.config';
import { GlobalConfig } from './config/global.config';
import { HomeAssistantConfig } from './integrations/home-assistant/home-assistant.config';
import { OmronD6tConfig } from './integrations/omron-d6t/omron-d6t.config';
import { GridEyeConfig } from './integrations/grid-eye/grid-eye.config';
import { BluetoothClassicConfig } from './integrations/bluetooth-classic/bluetooth-classic.config';
import { GpioConfig } from './integrations/gpio/gpio.config';
import { ShellConfig } from './integrations/shell/shell.config';
import { XiaomiMiConfig } from './integrations/xiaomi-mi/xiaomi-mi.config';
import { EntitiesConfig } from './entities/entities.config';
import { LoggerConfig } from './config/logger.config';
import { MqttConfig } from './integrations/mqtt/mqtt.config';
import * as jf from 'joiful';

export class AppConfig {
@(jf.object().required())
global: GlobalConfig = new GlobalConfig();
@(jf.object().required())
logger: LoggerConfig = new LoggerConfig();
@(jf.object().required())
cluster: ClusterConfig = new ClusterConfig();
@(jf.object().required())
entities: EntitiesConfig = new EntitiesConfig();
@(jf.object().required())
bluetoothLowEnergy: BluetoothLowEnergyConfig = new BluetoothLowEnergyConfig();
@(jf.object().required())
bluetoothClassic: BluetoothClassicConfig = new BluetoothClassicConfig();
@(jf.object().required())
omronD6t: OmronD6tConfig = new OmronD6tConfig();
@(jf.object().required())
gridEye: GridEyeConfig = new GridEyeConfig();
@(jf.object().required())
gpio: GpioConfig = new GpioConfig();
@(jf.object().required())
shell: ShellConfig = new ShellConfig();
@(jf.object().required())
xiaomiMi: XiaomiMiConfig = new XiaomiMiConfig();
@(jf.object().required())
homeAssistant: HomeAssistantConfig = new HomeAssistantConfig();
@(jf.object().required())
mqtt: MqttConfig = new MqttConfig();
}
9 changes: 9 additions & 0 deletions src/cluster/cluster.config.ts
@@ -1,9 +1,18 @@
import * as jf from 'joiful';

export class ClusterConfig {
@(jf.string().optional())
networkInterface?: string;
@(jf.number().integer().min(0).max(65353).required())
port = 6425;
@(jf.number().integer().min(0).required())
timeout = 60;
@(jf.number().integer().min(0).optional())
weight?: number;
@(jf.number().integer().min(0).optional())
quorum?: number;
@(jf.boolean().required())
autoDiscovery = true;
@(jf.array({ elementClass: String }).required())
peerAddresses: string[] = [];
}
198 changes: 198 additions & 0 deletions src/config/config.service.spec.fail.yml
@@ -0,0 +1,198 @@
# Basic error cheking across standard Joiful/Joi functionality
#
# Errors coverd:
# - Type Errors: Boolean, Number, String, Class
# - Constraint Errors: Positive, Negative, Minimum, Maximum, Length, Whitelist
# - Format Errors: Incorrect Indentation, Misspelt Property, Missplaced Key, Bad Format (e.g. MAC Address)


global:
instanceName: test-instance
integrations:
- bluetoothLowEnergy
- bluetoothClassic
- omronD6t
- gridEye
- gpio
- shell
- xiaomiMi
- homeAssistant
- mqtt
- blueoothClassic # FORMAT ERROR: Missspelt Property
logger:
elasticsearch:
enabled: yes # TYPE ERROR: Boolean Required
auth: # TYPE ERROR: Auth Class Required
# username: user
password: password
apiKey: "mykey"
# apiKey:
# id: "my id"
# api_key: "my api key"
node: http://192.168.0.20:33333
indexPrefix: <indexPrefix>-<date>
cluster:
networkInterface: eth0
port: 6425
timeout: -3 # CONSTRAINT ERROR: Positive Required
weight: 50
quorum: 1
autoDiscovery: false
peerAddresses:
- 192.168.1.10:6425
- 192.168.1.11:6425
entities:
behaviors:
debounced_entity:
debounce:
wait: 0.75
maxWait: 2
leading: null # TYPE ERROR: Boolean Required
trailing: false
leading_debounced_entity:
debounce:
wait: 0.75
maxWait: 2
leading: true
trailing: false
rolling_average_entity:
rollingAverage:
window: 60
chained_entity:
debounce:
wait: 0.75
maxWait: 2
leading: true
trailing: true
rollingAverage:
window: 60
bluetoothLowEnergy:
hciDeviceId: 0
whitelist:
- 123456
- 7750fb4dab70
- "ebef1234567890-55555-333"
- "ebef1234567890-55555-444"
- "ebef1234567890-55555-555"
whitelistRegex: false
blacklist: []
blacklistRegex: false
allowlist: []
allowlistRegex: false
denylist: []
denylistRegex: false
processIBeacon: true
onlyIBeacon: false
majorMask: 0xFFFF
minorMask: 0xGHIG # CONSTRAINT ERROR: Hex Required
batteryMask: 0x0000FF00
instanceBeaconEnabled: true
instanceBeaconMajor: 1
instanceBeaconMinor: 555
timeout: 30
updateFrequence: 55 # FORMAT ERROR: Key Misspelt
# updateFrequency: 55 # FORMAT ERROR: Missing Key
maxDistance: 44.4
tagOverrides:
ebef1234567890-55555-333:
name: iBeacon 1
measuredPower: 33 # CONSTRAINT ERROR: Positive Required
batteryMask: 0xFFFFFFFFFFFF # CONSTRAINT ERROR: Maximum (0xFFFFFFFF) Exceeded
ebef1234567890-55555-444:
name: iBeacon 2
timeout: 120 # FORMAT ERROR: Missplaced Property
bluetoothClassic:
hciDeviceId: 1
interval: 20
scanTimeLimit: 21
timeoutCycles: -2.5 # CONSTRAINT ERROR: Minimum (1) Exceeded
preserveState: true
inquireFromStart: true
minRssi: # TYPE ERROR: Unrecognised Type
'08:05:90:ed:3b:60': 10 # CONTEXT: Negative Required
'08:05:90:ed:32:1Z': -10 # CONTEXT: MAC Required
default: -20
addresses:
- '08:05:90:ED:3B:60'
- '77:50:fb:4d:ab:7G' # TYPE ERROR: MAC Required
- '77:50' # TYPE ERROR: MAC Required
- '77::fb:4d:ab:70' # TYPE ERROR: MAC Required
- '77:50:fb:4d:ab:70'
entityOverrides:
ebef1234567890-55555-333:
id: 333 # TYPE ERROR: String Required
omronD6t:
busNumber: 3
address: 0x1d
deltaThreshold: 2
heatmap:
enabled: 123 # TYPE ERROR: Boolean Required
minTemperature: 16
maxTemperature: 30
rotation: 90
drawTemperatures: false
gridEye:
busNumber: 1
address: 0x69
deltaThreshold: 2
heatmap:
enabled: true
minTemperature: "23" # TYPE ERROR: Number Required
maxTemperature: 30
rotation: 179 # CONSTRAINT ERROR: Whitelist Required
drawTemperatures: true
gpio:
binarySensors:
- name: PIR Sensor
pin: 23
- name: Radar
pin: 24
deviceClass: fake-device-class # TYPE ERROR: Whitelist Required
switches:
- name: Test Switch
pin: 17
icon: my_icon.png
shell:
sensors:
- name: Simple Test
command: echo test
cron: '* * * * *'
- name: Regex Test
command: echo 'test 123'
cron: '* * * * */2'
regex: '[1-9]+'
deviceClass: 'timestamp'
icon: 'mdi:test'
unitOfMeasurement: 'tests'
switches: # FORMAT ERROR: Incorrect Indentation -> Bad Key & Missing Key Errors
- name: Test Switch
onCommand: echo on
offCommand: echo off
xiaomiMi:
hciDeviceId: 0
sensors:
- address: a4:c1:38:32:12:f9 # FORMAT ERROR: -> Hex Required / Length Exceeded Errors
name: Xiaomi 1
- address: a4c138131f9e
name: Xiaomi 2
bindKey: 2dda568adf78
homeAssistant:
mqttUrl: mqtt://server.domain.com:18834
# discoveryPrefix: homeassistant # FORMAT ERROR: Missing Key
discoveryPrefi: homeassistant # FORMAT ERROR: Unrecognised Key
mqttOptions:
username: mqtt
password: mqtt
rejectUnauthorized: false
sendAttributes: false
sendMqttRoom: false
mqttRoomPrefix: 'room-assistant/mqtt-room'
mqtt:
mqttUrl: mttq://server.domain.com:18834 # FORMAT ERROR: Scheme Required
mqttOptions:
username: mqtt
password: mqtt
rejectUnauthorized: false
baseTopic: ra/entity
qos: 100 # CONSTRAINT ERROR: Whitelist Required
retain: false

0 comments on commit 7acc37f

Please sign in to comment.