Files
houseplan-card/scripts/config-schema.json
T
claude[bot]andCodex 870237f3fb feat(backend): LED strips are stored, normalised and transferred (#780)
Stage 1 of #780 — the data model. A space carries an optional
`led_strips: [{id, points, marker, active?}]` (custom_components/houseplan/
led_strips.py, pure, strict mypy).

- Type schema inside SPACE_SCHEMA: 2–50 finite numeric points (no strings,
  booleans, NaN or off-canvas values), ≤50 strips per space including hidden
  shapes, strict boolean `active`, marker = non-empty string or null.
- A config-level step after coordinate canonicalisation judges the shape
  (two distinct points, non-zero length, a closed strip needs three distinct
  vertices, a hidden shape needs a marker, unique ids per space) and the links
  in the order the spec fixes: duplicates are rejected before any
  normalisation (two links to the same missing id still conflict); a link to
  a marker that is not live becomes an unbound strip (marker null, active
  true, id and points kept), so a client that does not know strips can delete
  a bound marker without its save failing; a live marker with an empty space
  adopts the strip's space; a non-empty foreign space rejects the write.
- config/set answers with `led_strips: {unbound, space_adopted}` when the
  write was normalised, so a new client re-reads; old clients ignore it.
- Space import remaps links through the marker id map; a skipped or
  virtualised duplicate leaves the strip unbound; a coinciding old id never
  binds. Plan-only export keeps geometry and nulls every link. Import details
  report `unbound_led_strips`, computed by the server, never read from the file.
- Coordinates get JSON-noise cleanup only, like stairs (face contacts are
  off-lattice), in both canonicalisers with a shared fixture case.
- Support package: counters only (total/unbound/hidden), no coordinates or ids.

Tests: tests_backend/test_led_strips.py (41, pure), test_ha_import_export
(6 cases: full round trip with a hidden shape, orphan count, remap against a
coinciding id, skip and virtual duplicates, plan-only), test_ha_websocket
(old client deletes a bound marker → save stands, counters, foreign space
rejects without a new revision). Full backend with the HA harness: 969 passed.
Mutating the shape check, the duplicate check, the orphan normalisation or the
space adoption each turns the pure suite red.

Issue: #780
User-Visible: no
2026-10-02 20:54:49 +03:00

1642 lines
39 KiB
JSON

{
"_comment": "#33: generated by scripts/dump-config-schema.py — do not edit by hand",
"fields": {
"config": {
"allowExtra": true
},
"config.markers": {
"default": {
"factory": "list"
},
"required": false
},
"config.markers[]": {
"allowExtra": true
},
"config.markers[].angle": {
"max": 360,
"min": -360,
"nullable": true,
"required": false,
"type": "float"
},
"config.markers[].area": {
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].binding": {
"maxLength": 500,
"minLength": 1,
"opaque": "Match('^(device:.+|entity:.+|virtual)$', msg=None)",
"required": true,
"type": "str"
},
"config.markers[].controls": {
"list": {
"maxLength": 500,
"type": "str"
},
"maxLength": 200,
"nullable": true,
"required": false
},
"config.markers[].description": {
"maxLength": 4000,
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].display": {
"required": false,
"variants": [
{
"const": "badge"
},
{
"const": "ripple"
},
{
"const": "icon_ripple"
},
{
"const": "value"
},
{
"const": "static_icon"
},
{
"const": "value_static_icon"
},
{
"type": "null"
}
]
},
"config.markers[].glow_color": {
"nullable": true,
"required": false
},
"config.markers[].glow_color.bri": {
"max": 1.0,
"min": 0.01,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.markers[].glow_color.c": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": true
},
"config.markers[].glow_radius_cm": {
"max": 10000,
"min": 10,
"nullable": true,
"required": false,
"type": "float"
},
"config.markers[].hidden": {
"required": false,
"type": "bool"
},
"config.markers[].icon": {
"maxLength": 500,
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].id": {
"required": true,
"type": "str"
},
"config.markers[].is_light": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].light_entity": {
"required": false,
"type": "object"
},
"config.markers[].link": {
"maxLength": 2000,
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].model": {
"maxLength": 500,
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].name": {
"maxLength": 500,
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].pdfs": {
"required": false
},
"config.markers[].pdfs[]": {
"allowExtra": true
},
"config.markers[].pdfs[].name": {
"maxLength": 500,
"required": true,
"type": "str"
},
"config.markers[].pdfs[].url": {
"maxLength": 2000,
"required": true,
"type": "str"
},
"config.markers[].radar": {
"allowExtra": true,
"nullable": true,
"required": false
},
"config.markers[].removed": {
"required": false,
"type": "bool"
},
"config.markers[].ripple_color": {
"nullable": true,
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.markers[].ripple_size": {
"max": 20,
"min": 1,
"nullable": true,
"required": false,
"type": "float"
},
"config.markers[].room_id": {
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].size": {
"max": 6,
"min": 0.2,
"nullable": true,
"required": false,
"type": "float"
},
"config.markers[].space": {
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].tap_action": {
"required": false,
"variants": [
{
"const": "info"
},
{
"const": "more-info"
},
{
"const": "toggle"
},
{
"const": "run"
},
{
"const": "none"
},
{
"const": "cover"
},
{
"type": "null"
}
]
},
"config.markers[].tap_confirm": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].tap_target": {
"maxLength": 500,
"nullable": true,
"opaque": "Match('^(automation|script|scene)\\\\.[A-Za-z0-9_]+$', msg=None)",
"required": false,
"type": "str"
},
"config.markers[].toggle_entity": {
"required": false,
"type": "object"
},
"config.markers[].use_climate_temp": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].vacuum": {
"nullable": true,
"required": false
},
"config.markers[].vacuum.calibration": {
"required": false
},
"config.markers[].vacuum.calibration.*[]": {
"opaque": "<function _finite>"
},
"config.markers[].vacuum.live": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].vacuum.map_routes": {
"list": {
"allowExtra": true,
"object": true
},
"maxLength": 32,
"nullable": true,
"required": false
},
"config.markers[].vacuum.room_highlight": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].vacuum.segment_map": {
"required": false
},
"config.markers[].vacuum.segment_map.*": {
"type": "str"
},
"config.markers[].vacuum.source": {
"nullable": true,
"required": false,
"type": "str"
},
"config.markers[].vacuum.trail": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.markers[].vacuum.trail_mode": {
"enum": [
"always",
"cleaning",
"never"
],
"nullable": true,
"required": false
},
"config.markers[].value_badge": {
"allowExtra": true,
"nullable": true,
"required": false
},
"config.markers[].value_badge.enabled": {
"required": false,
"type": "object"
},
"config.markers[].value_badge.position": {
"required": false,
"type": "object"
},
"config.markers[].value_badge.source": {
"allowExtra": true,
"nullable": true,
"required": false
},
"config.markers[].value_source": {
"allowExtra": true,
"nullable": true,
"required": false
},
"config.model_version": {
"max": 1000000,
"min": 0,
"required": false,
"type": "int"
},
"config.settings": {
"allowExtra": true,
"default": {
"factory": "dict"
},
"required": false
},
"config.settings.bg_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.settings.bg_mode": {
"enum": [
"daynight",
"static"
],
"required": false
},
"config.settings.decor_default_style": {
"required": false
},
"config.settings.decor_default_style.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.settings.decor_default_style.fill": {
"required": false,
"type": "bool"
},
"config.settings.decor_default_style.fill_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.settings.decor_default_style.fill_opacity": {
"max": 1,
"min": 0,
"required": false,
"type": "float"
},
"config.settings.decor_default_style.opacity": {
"max": 1,
"min": 0,
"required": false,
"type": "float"
},
"config.settings.decor_default_style.width_cm": {
"max": 100,
"min": 0.1,
"required": false,
"type": "float"
},
"config.settings.fill_colors": {
"required": false
},
"config.settings.fill_colors.*.a": {
"max": 1,
"min": 0,
"required": true,
"type": "float"
},
"config.settings.fill_colors.*.c": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": true
},
"config.settings.glow_radius_cm": {
"max": 10000,
"min": 10,
"required": false,
"type": "float"
},
"config.settings.known_devices": {
"required": false
},
"config.settings.known_devices[]": {
"maxLength": 500,
"type": "str"
},
"config.settings.marker_area_snapshot": {
"required": false
},
"config.settings.marker_area_snapshot.<All(<class 'str'>, Length(min=1, max=500), msg=None)>.area": {
"maxLength": 500,
"minLength": 1,
"required": true,
"type": "str"
},
"config.settings.marker_area_snapshot.<All(<class 'str'>, Length(min=1, max=500), msg=None)>.binding": {
"maxLength": 500,
"minLength": 1,
"opaque": "Match('^(?:device|entity):.+$', msg=None)",
"required": true,
"type": "str"
},
"config.settings.moon": {
"required": false,
"type": "bool"
},
"config.settings.new_device_ids": {
"required": false
},
"config.settings.new_device_ids[]": {
"maxLength": 500,
"type": "str"
},
"config.settings.north_deg": {
"opaque": "<function _north_deg>",
"required": false
},
"config.settings.radar": {
"allowExtra": true,
"required": false
},
"config.settings.show_room_tooltip": {
"required": false,
"type": "bool"
},
"config.settings.summary_panel": {
"required": false,
"variants": [
{
"allowExtra": true,
"object": true,
"opaque": "<function _summary_panel_invariants>"
},
{
"opaque": "<function _future_summary_panel>"
}
]
},
"config.settings.sun_ray_origin": {
"enum": [
"inner",
"outer"
],
"required": false
},
"config.settings.sun_rays": {
"required": false,
"type": "bool"
},
"config.settings.volumetric_view": {
"required": false,
"type": "bool"
},
"config.settings.weather_entity": {
"maxLength": 500,
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces": {
"required": true
},
"config.spaces[]": {
"allowExtra": true
},
"config.spaces[].aspect": {
"removed": true
},
"config.spaces[].cell_cm": {
"max": 1000.0,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor": {
"required": false
},
"config.spaces[].decor[]<ellipse|rect>": {
"allowExtra": true
},
"config.spaces[].decor[]<ellipse|rect>.angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.fill": {
"required": false,
"type": "bool"
},
"config.spaces[].decor[]<ellipse|rect>.fill_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.fill_opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.h": {
"max": 5000.0,
"min": 0.001,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<ellipse|rect>.id": {
"required": true,
"type": "str"
},
"config.spaces[].decor[]<ellipse|rect>.kind": {
"enum": [
"ellipse",
"rect"
],
"required": true
},
"config.spaces[].decor[]<ellipse|rect>.opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.w": {
"max": 5000.0,
"min": 0.001,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<ellipse|rect>.width": {
"max": 30,
"min": 0.1,
"required": false,
"type": "float"
},
"config.spaces[].decor[]<ellipse|rect>.width_cm": {
"max": 100,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<ellipse|rect>.x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<ellipse|rect>.y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<furniture>": {
"allowExtra": true
},
"config.spaces[].decor[]<furniture>.angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<furniture>.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<furniture>.flip_h": {
"required": false,
"type": "bool"
},
"config.spaces[].decor[]<furniture>.flip_v": {
"required": false,
"type": "bool"
},
"config.spaces[].decor[]<furniture>.h": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<furniture>.id": {
"required": true,
"type": "str"
},
"config.spaces[].decor[]<furniture>.kind": {
"const": "furniture",
"required": true
},
"config.spaces[].decor[]<furniture>.opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<furniture>.symbol": {
"maxLength": 32,
"minLength": 1,
"opaque": "Match('^[a-z0-9_]+$', msg=None)",
"required": true,
"type": "str"
},
"config.spaces[].decor[]<furniture>.w": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<furniture>.width": {
"max": 30,
"min": 0.1,
"required": false,
"type": "float"
},
"config.spaces[].decor[]<furniture>.width_cm": {
"max": 100,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<furniture>.x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<furniture>.y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<image>": {
"allowExtra": true
},
"config.spaces[].decor[]<image>.angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<image>.asset_id": {
"opaque": "Match('^[0-9a-f]{64}$', msg=None)",
"required": true,
"type": "str"
},
"config.spaces[].decor[]<image>.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<image>.flip_h": {
"required": false,
"type": "bool"
},
"config.spaces[].decor[]<image>.flip_v": {
"required": false,
"type": "bool"
},
"config.spaces[].decor[]<image>.h": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<image>.id": {
"required": true,
"type": "str"
},
"config.spaces[].decor[]<image>.kind": {
"const": "image",
"required": true
},
"config.spaces[].decor[]<image>.opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<image>.w": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<image>.width": {
"max": 30,
"min": 0.1,
"required": false,
"type": "float"
},
"config.spaces[].decor[]<image>.width_cm": {
"max": 100,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<image>.x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<image>.y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<line>": {
"allowExtra": true
},
"config.spaces[].decor[]<line>.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<line>.id": {
"required": true,
"type": "str"
},
"config.spaces[].decor[]<line>.kind": {
"const": "line",
"required": true
},
"config.spaces[].decor[]<line>.line_style": {
"enum": [
"dashed",
"solid"
],
"required": false
},
"config.spaces[].decor[]<line>.opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<line>.width": {
"max": 30,
"min": 0.1,
"required": false,
"type": "float"
},
"config.spaces[].decor[]<line>.width_cm": {
"max": 100,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<line>.x1": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<line>.x2": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<line>.y1": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<line>.y2": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<text>": {
"allowExtra": true
},
"config.spaces[].decor[]<text>.angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<text>.attr": {
"maxLength": 64,
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].decor[]<text>.color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].decor[]<text>.entity": {
"maxLength": 255,
"minLength": 3,
"nullable": true,
"opaque": "Match('^[a-z0-9_]+\\\\.[a-z0-9_]+$', msg=None)",
"required": false,
"type": "str"
},
"config.spaces[].decor[]<text>.id": {
"required": true,
"type": "str"
},
"config.spaces[].decor[]<text>.kind": {
"const": "text",
"required": true
},
"config.spaces[].decor[]<text>.opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<text>.scale": {
"max": 20.0,
"min": 0.15,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<text>.size": {
"enum": [
"l",
"m",
"s"
],
"required": false
},
"config.spaces[].decor[]<text>.size_cm": {
"max": 2000.0,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<text>.text": {
"maxLength": 200,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].decor[]<text>.unit": {
"maxLength": 16,
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].decor[]<text>.width": {
"max": 30,
"min": 0.1,
"required": false,
"type": "float"
},
"config.spaces[].decor[]<text>.width_cm": {
"max": 100,
"min": 0.1,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].decor[]<text>.x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].decor[]<text>.y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].id": {
"opaque": "Match('^[a-z0-9_-]{1,64}$', msg=None)",
"required": true,
"type": "str"
},
"config.spaces[].led_strips": {
"required": false
},
"config.spaces[].led_strips[]": {
"allowExtra": true
},
"config.spaces[].led_strips[].active": {
"opaque": "<function _strict_bool>",
"required": false
},
"config.spaces[].led_strips[].id": {
"opaque": "<function _strip_id>",
"required": true
},
"config.spaces[].led_strips[].marker": {
"default": {
"factory": "NoneType"
},
"opaque": "<function _marker_ref>",
"required": false
},
"config.spaces[].led_strips[].points": {
"required": true
},
"config.spaces[].led_strips[].points[][]": {
"opaque": "<function _coordinate>"
},
"config.spaces[].open_spans": {
"required": false
},
"config.spaces[].open_spans[]": {
"opaque": "<function _open_span>"
},
"config.spaces[].openings": {
"required": false
},
"config.spaces[].openings[]": {
"allowExtra": true
},
"config.spaces[].openings[].angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].openings[].contact": {
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].openings[].flip_h": {
"required": false,
"type": "bool"
},
"config.spaces[].openings[].flip_v": {
"required": false,
"type": "bool"
},
"config.spaces[].openings[].host": {
"required": false
},
"config.spaces[].openings[].host<partition>.id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].openings[].host<partition>.kind": {
"const": "partition",
"required": true
},
"config.spaces[].openings[].host<partition>.t": {
"max": 1,
"min": 0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].openings[].host<wall>.id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].openings[].host<wall>.kind": {
"const": "wall",
"required": true
},
"config.spaces[].openings[].host<wall>.t": {
"max": 1,
"min": 0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].openings[].id": {
"required": true,
"type": "str"
},
"config.spaces[].openings[].invert": {
"required": false,
"type": "bool"
},
"config.spaces[].openings[].length": {
"max": 5000.0,
"min": 0.001,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].openings[].lock": {
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].openings[].type": {
"required": true,
"variants": [
{
"const": "door"
},
{
"const": "window"
},
{
"const": "gate"
},
{
"const": "passage"
}
]
},
"config.spaces[].openings[].x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].openings[].y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].partitions": {
"required": false
},
"config.spaces[].partitions[]": {
"allowExtra": true
},
"config.spaces[].partitions[].a": {
"required": true
},
"config.spaces[].partitions[].a[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].partitions[].b": {
"required": true
},
"config.spaces[].partitions[].b[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].partitions[].cm": {
"max": 100,
"min": 0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].partitions[].id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].plan_angle": {
"max": 360.0,
"min": -360.0,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].plan_aspect": {
"max": 20,
"min": 0.05,
"nullable": true,
"required": false,
"type": "float"
},
"config.spaces[].plan_scale": {
"max": 100.0,
"min": 0.01,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].plan_scale_x": {
"max": 100.0,
"min": 0.01,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].plan_scale_y": {
"max": 100.0,
"min": 0.01,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].plan_url": {
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].plan_x": {
"max": 5000.0,
"min": -5000.0,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].plan_y": {
"max": 5000.0,
"min": -5000.0,
"nullable": true,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].room_drafts": {
"required": false
},
"config.spaces[].room_drafts[]": {
"allowExtra": true
},
"config.spaces[].room_drafts[].id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].room_drafts[].points": {
"required": true
},
"config.spaces[].room_drafts[].points[][]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].room_drafts[].segments": {
"required": true
},
"config.spaces[].room_drafts[].segments[]": {
"allowExtra": true
},
"config.spaces[].room_drafts[].segments[].cm": {
"max": 100,
"min": 0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].room_drafts[].segments[].id": {
"maxLength": 64,
"minLength": 1,
"required": false,
"type": "str"
},
"config.spaces[].rooms": {
"required": true
},
"config.spaces[].rooms[]": {
"allowExtra": true
},
"config.spaces[].rooms[].area": {
"maxLength": 500,
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].rooms[].h": {
"max": 5000.0,
"min": 0.001,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].rooms[].id": {
"maxLength": 500,
"required": true,
"type": "str"
},
"config.spaces[].rooms[].name": {
"maxLength": 500,
"required": true,
"type": "str"
},
"config.spaces[].rooms[].open_to": {
"required": false
},
"config.spaces[].rooms[].open_to[]": {
"maxLength": 500,
"type": "str"
},
"config.spaces[].rooms[].poly": {
"required": false
},
"config.spaces[].rooms[].poly[][]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].rooms[].settings": {
"allowExtra": true,
"nullable": true,
"required": false
},
"config.spaces[].rooms[].settings.custom_fill": {
"nullable": true,
"required": false
},
"config.spaces[].rooms[].settings.custom_fill.a": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].rooms[].settings.custom_fill.c": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": true
},
"config.spaces[].rooms[].settings.fill_mode": {
"enum": [
"custom",
"glow",
"light",
"lqi",
"none",
"temp"
],
"nullable": true,
"required": false
},
"config.spaces[].rooms[].settings.glow": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.spaces[].rooms[].settings.hum_source": {
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].rooms[].settings.label_scale": {
"max": 3,
"min": 0.5,
"nullable": true,
"required": false,
"type": "float"
},
"config.spaces[].rooms[].settings.name_scale": {
"max": 3,
"min": 0.5,
"nullable": true,
"required": false,
"type": "float"
},
"config.spaces[].rooms[].settings.temp_max": {
"opaque": "<function _finite_number_or_none>",
"required": false
},
"config.spaces[].rooms[].settings.temp_min": {
"opaque": "<function _finite_number_or_none>",
"required": false
},
"config.spaces[].rooms[].settings.temp_source": {
"nullable": true,
"required": false,
"type": "str"
},
"config.spaces[].rooms[].w": {
"max": 5000.0,
"min": 0.001,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].rooms[].wall_ids": {
"required": false
},
"config.spaces[].rooms[].wall_ids[]": {
"maxLength": 64,
"minLength": 1,
"type": "str"
},
"config.spaces[].rooms[].x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].rooms[].y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].segments": {
"removed": true
},
"config.spaces[].settings": {
"allowExtra": true,
"required": false
},
"config.spaces[].settings.bg_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].settings.bg_mode": {
"enum": [
"daynight",
"static"
],
"nullable": true,
"required": false
},
"config.spaces[].settings.card_font_scale": {
"max": 3,
"min": 0.5,
"required": false,
"type": "float"
},
"config.spaces[].settings.custom_fill": {
"nullable": true,
"required": false
},
"config.spaces[].settings.custom_fill.a": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].settings.custom_fill.c": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": true
},
"config.spaces[].settings.fill_mode": {
"enum": [
"custom",
"glow",
"light",
"lqi",
"none",
"temp"
],
"required": false
},
"config.spaces[].settings.glow_enabled": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.hide_decor": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.hide_openings": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.label_hum": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.label_light": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.label_lqi": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.label_temp": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.north_deg": {
"nullable": true,
"opaque": "<function _north_deg>",
"required": false
},
"config.spaces[].settings.room_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].settings.room_opacity": {
"max": 1,
"min": 0,
"required": false,
"type": "float"
},
"config.spaces[].settings.show_borders": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.show_lqi": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.show_names": {
"required": false,
"type": "bool"
},
"config.spaces[].settings.sun_rays": {
"nullable": true,
"required": false,
"type": "bool"
},
"config.spaces[].settings.temp_max": {
"required": false,
"type": "float"
},
"config.spaces[].settings.temp_min": {
"required": false,
"type": "float"
},
"config.spaces[].stairs": {
"required": false
},
"config.spaces[].stairs[]": {
"allowExtra": true
},
"config.spaces[].stairs[].angle": {
"max": 360.0,
"min": -360.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].stairs[].color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].stairs[].direction": {
"enum": [
"backward",
"clockwise",
"counterclockwise",
"forward"
],
"required": true
},
"config.spaces[].stairs[].fill_color": {
"opaque": "Match('\\\\A#[0-9a-fA-F]{6}\\\\Z', msg=None)",
"required": false
},
"config.spaces[].stairs[].fill_opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].stairs[].id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].stairs[].kind": {
"enum": [
"spiral",
"straight"
],
"required": true
},
"config.spaces[].stairs[].length": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].stairs[].opacity": {
"max": 1.0,
"min": 0.0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].stairs[].radius": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].stairs[].target_space_id": {
"nullable": true,
"opaque": "Match('^[a-z0-9_-]{1,64}$', msg=None)",
"required": false,
"type": "str"
},
"config.spaces[].stairs[].width": {
"max": 5000.0,
"min": 1e-07,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].stairs[].x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].stairs[].y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].title": {
"required": true,
"type": "str"
},
"config.spaces[].view_box": {
"opaque": "<function _view_box>",
"required": true
},
"config.spaces[].wall_columns": {
"required": false
},
"config.spaces[].wall_columns[]": {
"allowExtra": true
},
"config.spaces[].wall_columns[].angle": {
"max": 90,
"min": 0,
"opaque": "<function _finite>",
"required": false
},
"config.spaces[].wall_columns[].center": {
"required": true
},
"config.spaces[].wall_columns[].center[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].wall_columns[].cm": {
"max": 150,
"min": 1,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].wall_columns[].id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].wall_columns[].shape": {
"enum": [
"circle",
"square"
],
"required": true
},
"config.spaces[].wall_segments": {
"required": false
},
"config.spaces[].wall_segments[]": {
"allowExtra": true
},
"config.spaces[].wall_segments[].a": {
"required": true
},
"config.spaces[].wall_segments[].a[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].wall_segments[].b": {
"required": true
},
"config.spaces[].wall_segments[].b[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].wall_segments[].cm": {
"max": 100,
"min": 0,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].wall_segments[].id": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].walls": {
"required": false
},
"config.spaces[].walls[]": {
"allowExtra": true
},
"config.spaces[].walls[].a": {
"required": false
},
"config.spaces[].walls[].a[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].walls[].b": {
"required": false
},
"config.spaces[].walls[].b[]": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>"
},
"config.spaces[].walls[].cm": {
"max": 100,
"min": 1,
"opaque": "<function _finite>",
"required": true
},
"config.spaces[].walls[].key": {
"maxLength": 64,
"minLength": 1,
"required": true,
"type": "str"
},
"config.spaces[].zero_wall_style": {
"enum": [
"dashed",
"solid"
],
"required": false
},
"layout.*": {
"allowExtra": true
},
"layout.*.x": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
},
"layout.*.y": {
"max": 5000.0,
"min": -5000.0,
"opaque": "<function _finite>",
"required": true
}
}
}