Compare commits
10 Commits
0.10.2
...
0.10.9-con
| Author | SHA1 | Date | |
|---|---|---|---|
|
d8780b1790
|
|||
|
3d5010b4a1
|
|||
|
b471ab5edc
|
|||
|
3e0a1b49ab
|
|||
|
befdc8a46c
|
|||
|
da16c59238
|
|||
|
5f3185894d
|
|||
|
fb828c9a2c
|
|||
|
064ee6bbed
|
|||
|
d39bcfce26
|
@@ -19,6 +19,7 @@ from apps.abstraction.vendors import (
|
|||||||
tasmota,
|
tasmota,
|
||||||
hottis_pv_modbus,
|
hottis_pv_modbus,
|
||||||
hottis_wago_modbus,
|
hottis_wago_modbus,
|
||||||
|
hottis_wifi_relay,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -42,6 +43,7 @@ for vendor_name, vendor_module in [
|
|||||||
("tasmota", tasmota),
|
("tasmota", tasmota),
|
||||||
("hottis_pv_modbus", hottis_pv_modbus),
|
("hottis_pv_modbus", hottis_pv_modbus),
|
||||||
("hottis_wago_modbus", hottis_wago_modbus),
|
("hottis_wago_modbus", hottis_wago_modbus),
|
||||||
|
("hottis_wifi_relay", hottis_wifi_relay),
|
||||||
]:
|
]:
|
||||||
for (device_type, direction), handler in vendor_module.HANDLERS.items():
|
for (device_type, direction), handler in vendor_module.HANDLERS.items():
|
||||||
key = (device_type, vendor_name, direction)
|
key = (device_type, vendor_name, direction)
|
||||||
|
|||||||
38
apps/abstraction/vendors/hottis_wifi_relay.py
vendored
Normal file
38
apps/abstraction/vendors/hottis_wifi_relay.py
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"""Hottis WiFi Relay vendor transformations."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def transform_relay_to_vendor(payload: dict[str, Any]) -> str:
|
||||||
|
"""Transform abstract relay payload to Hottis WiFi Relay format.
|
||||||
|
|
||||||
|
Hottis WiFi Relay expects plain text 'on' or 'off' (not JSON).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- Abstract: {'power': 'on'}
|
||||||
|
- Hottis WiFi Relay: 'ON'
|
||||||
|
"""
|
||||||
|
power = payload.get("power", "off").upper()
|
||||||
|
return power
|
||||||
|
|
||||||
|
|
||||||
|
def transform_relay_to_abstract(payload: str) -> dict[str, Any]:
|
||||||
|
"""Transform Hottis WiFi Relay relay payload to abstract format.
|
||||||
|
|
||||||
|
Hottis WiFi Relay sends plain text 'on' or 'off'.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- Hottis WiFi Relay: 'ON'
|
||||||
|
- Abstract: {'power': 'on'}
|
||||||
|
"""
|
||||||
|
return {"power": payload.strip().lower()}
|
||||||
|
|
||||||
|
|
||||||
|
# Registry of handlers for this vendor
|
||||||
|
HANDLERS = {
|
||||||
|
("relay", "to_vendor"): transform_relay_to_vendor,
|
||||||
|
("relay", "to_abstract"): transform_relay_to_abstract,
|
||||||
|
}
|
||||||
@@ -48,11 +48,11 @@ class HeatingControlRequest(BaseModel):
|
|||||||
target: float # Target temperature
|
target: float # Target temperature
|
||||||
|
|
||||||
|
|
||||||
def get_room_devices(room_name: str) -> list[dict[str, Any]]:
|
def get_room_devices(room_id: str) -> list[dict[str, Any]]:
|
||||||
"""Get all devices in a specific room from layout.
|
"""Get all devices in a specific room from layout.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
room_name: Name of the room
|
room_id: ID of the room
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of device dicts with device_id, title, icon, rank, excluded
|
List of device dicts with device_id, title, icon, rank, excluded
|
||||||
@@ -63,7 +63,7 @@ def get_room_devices(room_name: str) -> list[dict[str, Any]]:
|
|||||||
layout = load_layout()
|
layout = load_layout()
|
||||||
|
|
||||||
for room in layout.rooms:
|
for room in layout.rooms:
|
||||||
if room.name == room_name:
|
if room.id == room_id:
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"device_id": device.device_id,
|
"device_id": device.device_id,
|
||||||
@@ -77,16 +77,16 @@ def get_room_devices(room_name: str) -> list[dict[str, Any]]:
|
|||||||
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=f"Room '{room_name}' not found"
|
detail=f"Room '{room_id}' not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/rooms/{room_name}/lights", status_code=status.HTTP_202_ACCEPTED)
|
@router.post("/rooms/{room_id}/lights", status_code=status.HTTP_202_ACCEPTED)
|
||||||
async def control_room_lights(room_name: str, request: LightsControlRequest) -> dict[str, Any]:
|
async def control_room_lights(room_id: str, request: LightsControlRequest) -> dict[str, Any]:
|
||||||
"""Control all lights (light and relay devices) in a room.
|
"""Control all lights (light and relay devices) in a room.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
room_name: Name of the room
|
room_id: ID of the room
|
||||||
request: Light control parameters
|
request: Light control parameters
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -95,7 +95,7 @@ async def control_room_lights(room_name: str, request: LightsControlRequest) ->
|
|||||||
from apps.api.main import load_devices, publish_abstract_set
|
from apps.api.main import load_devices, publish_abstract_set
|
||||||
|
|
||||||
# Get all devices in room
|
# Get all devices in room
|
||||||
room_devices = get_room_devices(room_name)
|
room_devices = get_room_devices(room_id)
|
||||||
|
|
||||||
# Filter out excluded devices
|
# Filter out excluded devices
|
||||||
room_device_ids = {d["device_id"] for d in room_devices if not d.get("excluded", False)}
|
room_device_ids = {d["device_id"] for d in room_devices if not d.get("excluded", False)}
|
||||||
@@ -112,7 +112,7 @@ async def control_room_lights(room_name: str, request: LightsControlRequest) ->
|
|||||||
if not light_devices:
|
if not light_devices:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=f"No light devices found in room '{room_name}'"
|
detail=f"No light devices found in room '{room_id}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Build payload
|
# Build payload
|
||||||
@@ -141,7 +141,7 @@ async def control_room_lights(room_name: str, request: LightsControlRequest) ->
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"room": room_name,
|
"room": room_id,
|
||||||
"command": "lights",
|
"command": "lights",
|
||||||
"payload": payload,
|
"payload": payload,
|
||||||
"affected_devices": affected_ids,
|
"affected_devices": affected_ids,
|
||||||
@@ -151,12 +151,12 @@ async def control_room_lights(room_name: str, request: LightsControlRequest) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.post("/rooms/{room_name}/heating", status_code=status.HTTP_202_ACCEPTED)
|
@router.post("/rooms/{room_id}/heating", status_code=status.HTTP_202_ACCEPTED)
|
||||||
async def control_room_heating(room_name: str, request: HeatingControlRequest) -> dict[str, Any]:
|
async def control_room_heating(room_id: str, request: HeatingControlRequest) -> dict[str, Any]:
|
||||||
"""Control all thermostats in a room.
|
"""Control all thermostats in a room.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
room_name: Name of the room
|
room_id: ID of the room
|
||||||
request: Heating control parameters
|
request: Heating control parameters
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -165,7 +165,7 @@ async def control_room_heating(room_name: str, request: HeatingControlRequest) -
|
|||||||
from apps.api.main import load_devices, publish_abstract_set
|
from apps.api.main import load_devices, publish_abstract_set
|
||||||
|
|
||||||
# Get all devices in room
|
# Get all devices in room
|
||||||
room_devices = get_room_devices(room_name)
|
room_devices = get_room_devices(room_id)
|
||||||
|
|
||||||
# Filter out excluded devices
|
# Filter out excluded devices
|
||||||
room_device_ids = {d["device_id"] for d in room_devices if not d.get("excluded", False)}
|
room_device_ids = {d["device_id"] for d in room_devices if not d.get("excluded", False)}
|
||||||
@@ -209,7 +209,7 @@ async def control_room_heating(room_name: str, request: HeatingControlRequest) -
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"room": room_name,
|
"room": room_id,
|
||||||
"command": "heating",
|
"command": "heating",
|
||||||
"payload": payload,
|
"payload": payload,
|
||||||
"affected_devices": affected_ids,
|
"affected_devices": affected_ids,
|
||||||
|
|||||||
@@ -898,3 +898,75 @@ devices:
|
|||||||
set: "zigbee2mqtt/0x842e14fffea72027/set"
|
set: "zigbee2mqtt/0x842e14fffea72027/set"
|
||||||
|
|
||||||
|
|
||||||
|
- device_id: keller_flur_licht
|
||||||
|
name: Keller Flur Licht
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wago_modbus
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "pulsegen/command/10/21"
|
||||||
|
state: "pulsegen/status/10"
|
||||||
|
- device_id: waschkueche_licht
|
||||||
|
name: Waschküche Licht
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wago_modbus
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "pulsegen/command/8/22"
|
||||||
|
state: "pulsegen/status/8"
|
||||||
|
- device_id: werkstatt_licht
|
||||||
|
name: Werkstatt Licht
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wago_modbus
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "pulsegen/command/7/19"
|
||||||
|
state: "pulsegen/status/7"
|
||||||
|
- device_id: sportzimmer_licht
|
||||||
|
name: Sportzimmer Licht
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wago_modbus
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "pulsegen/command/9/20"
|
||||||
|
state: "pulsegen/status/9"
|
||||||
|
- device_id: deckenlampe_patty
|
||||||
|
name: Deckenlampe Patty
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wago_modbus
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "pulsegen/command/4/16"
|
||||||
|
state: "pulsegen/status/4"
|
||||||
|
- device_id: regallampe_esszimmer
|
||||||
|
name: Regallampe Esszimmer
|
||||||
|
type: relay
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: hottis_wifi_relay
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
topics:
|
||||||
|
set: "IoT/WifiRelay1/State"
|
||||||
|
state: "IoT/WifiRelay1/State"
|
||||||
|
|
||||||
|
- device_id: herdlicht
|
||||||
|
name: Herdlicht
|
||||||
|
type: light
|
||||||
|
cap_version: "relay@1.0.0"
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
features:
|
||||||
|
power: true
|
||||||
|
brightness: true
|
||||||
|
topics:
|
||||||
|
state: "zigbee2mqtt/herdlicht"
|
||||||
|
set: "zigbee2mqtt/herdlicht/set"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
rooms:
|
rooms:
|
||||||
- id: Schlafzimmer
|
- id: schlafzimmer
|
||||||
name: Schlafzimmer
|
name: Schlafzimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: bettlicht_patty
|
- device_id: bettlicht_patty
|
||||||
@@ -34,7 +34,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 47
|
rank: 47
|
||||||
- id: Esszimmer
|
- id: esszimmer
|
||||||
name: Esszimmer
|
name: Esszimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: deckenlampe_esszimmer
|
- device_id: deckenlampe_esszimmer
|
||||||
@@ -61,10 +61,10 @@ rooms:
|
|||||||
title: Stehlampe Esszimmer Schrank
|
title: Stehlampe Esszimmer Schrank
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 82
|
rank: 82
|
||||||
# - device_id: kleine_lampe_rechts_esszimmer
|
- device_id: regallampe_esszimmer
|
||||||
# title: kleine Lampe rechts Esszimmer
|
title: Regallampe Esszimmer
|
||||||
# icon: 💡
|
icon: 💡
|
||||||
# rank: 90
|
rank: 90
|
||||||
- device_id: licht_schrank_esszimmer
|
- device_id: licht_schrank_esszimmer
|
||||||
title: Schranklicht Esszimmer
|
title: Schranklicht Esszimmer
|
||||||
icon: 💡
|
icon: 💡
|
||||||
@@ -81,7 +81,7 @@ rooms:
|
|||||||
title: Kontakt Straße links
|
title: Kontakt Straße links
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 97
|
rank: 97
|
||||||
- id: Wohnzimmer
|
- id: wohnzimmer
|
||||||
name: Wohnzimmer
|
name: Wohnzimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: lampe_naehtischchen_wohnzimmer
|
- device_id: lampe_naehtischchen_wohnzimmer
|
||||||
@@ -124,7 +124,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 138
|
rank: 138
|
||||||
- id: Küche
|
- id: kueche
|
||||||
name: Küche
|
name: Küche
|
||||||
devices:
|
devices:
|
||||||
- device_id: kueche_deckenlampe
|
- device_id: kueche_deckenlampe
|
||||||
@@ -144,6 +144,10 @@ rooms:
|
|||||||
title: Küche Fensterbank
|
title: Küche Fensterbank
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 144
|
rank: 144
|
||||||
|
- device_id: herdlicht
|
||||||
|
title: Herdlicht
|
||||||
|
icon: 💡
|
||||||
|
rank: 145
|
||||||
- device_id: thermostat_kueche
|
- device_id: thermostat_kueche
|
||||||
title: Kueche
|
title: Kueche
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
@@ -168,7 +172,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 155
|
rank: 155
|
||||||
- id: Arbeitszimmer Patty
|
- id: arbeitszimmer_patty
|
||||||
name: Arbeitszimmer Patty
|
name: Arbeitszimmer Patty
|
||||||
devices:
|
devices:
|
||||||
- device_id: leselampe_patty
|
- device_id: leselampe_patty
|
||||||
@@ -176,23 +180,27 @@ rooms:
|
|||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 160
|
rank: 160
|
||||||
- device_id: schranklicht_hinten_patty
|
- device_id: schranklicht_hinten_patty
|
||||||
title: Schranklicht hinten Patty
|
title: Schranklicht hinten
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 170
|
rank: 170
|
||||||
- device_id: schranklicht_vorne_patty
|
- device_id: schranklicht_vorne_patty
|
||||||
title: Schranklicht vorne Patty
|
title: Schranklicht vorne
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 180
|
rank: 180
|
||||||
- device_id: kugellampe_patty
|
- device_id: kugellampe_patty
|
||||||
title: Kugellampe Patty
|
title: Kugellampe
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 181
|
rank: 181
|
||||||
- device_id: licht_schreibtisch_patty
|
- device_id: licht_schreibtisch_patty
|
||||||
title: Licht Schreibtisch Patty
|
title: Licht Schreibtisch
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 182
|
rank: 182
|
||||||
|
- device_id: deckenlampe_patty
|
||||||
|
title: Deckenlampe
|
||||||
|
icon: 💡
|
||||||
|
rank: 183
|
||||||
- device_id: thermostat_patty
|
- device_id: thermostat_patty
|
||||||
title: Thermostat Patty
|
title: Thermostat
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 185
|
rank: 185
|
||||||
- device_id: kontakt_patty_garten_rechts
|
- device_id: kontakt_patty_garten_rechts
|
||||||
@@ -211,7 +219,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 189
|
rank: 189
|
||||||
- id: Arbeitszimmer Wolfgang
|
- id: arbeitszimmer_wolfgang
|
||||||
name: Arbeitszimmer Wolfgang
|
name: Arbeitszimmer Wolfgang
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_wolfgang
|
- device_id: thermostat_wolfgang
|
||||||
@@ -230,7 +238,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 202
|
rank: 202
|
||||||
- id: Flur
|
- id: flur
|
||||||
name: Flur
|
name: Flur
|
||||||
devices:
|
devices:
|
||||||
- device_id: deckenlampe_flur_oben
|
- device_id: deckenlampe_flur_oben
|
||||||
@@ -257,7 +265,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 235
|
rank: 235
|
||||||
- id: Sportzimmer
|
- id: sportzimmer
|
||||||
name: Sportzimmer
|
name: Sportzimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: sportlicht_regal
|
- device_id: sportlicht_regal
|
||||||
@@ -272,11 +280,15 @@ rooms:
|
|||||||
title: Sportlicht am Fernseher, Studierzimmer
|
title: Sportlicht am Fernseher, Studierzimmer
|
||||||
icon: 🏃
|
icon: 🏃
|
||||||
rank: 260
|
rank: 260
|
||||||
|
- device_id: sportzimmer_licht
|
||||||
|
title: Deckenlampe
|
||||||
|
icon: 💡
|
||||||
|
rank: 262
|
||||||
- device_id: sensor_sportzimmer
|
- device_id: sensor_sportzimmer
|
||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 265
|
rank: 265
|
||||||
- id: Bad Oben
|
- id: bad_oben
|
||||||
name: Bad Oben
|
name: Bad Oben
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_bad_oben
|
- device_id: thermostat_bad_oben
|
||||||
@@ -291,7 +303,7 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 272
|
rank: 272
|
||||||
- id: Bad Unten
|
- id: bad_unten
|
||||||
name: Bad Unten
|
name: Bad Unten
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_bad_unten
|
- device_id: thermostat_bad_unten
|
||||||
@@ -306,14 +318,19 @@ rooms:
|
|||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 282
|
rank: 282
|
||||||
- id: Waschküche
|
- id: waschkueche
|
||||||
name: Waschküche
|
name: Waschküche
|
||||||
devices:
|
devices:
|
||||||
- device_id: sensor_waschkueche
|
- device_id: sensor_waschkueche
|
||||||
title: Temperatur & Luftfeuchte
|
title: Temperatur & Luftfeuchte
|
||||||
icon: 🌡️
|
icon: 🌡️
|
||||||
rank: 290
|
rank: 290
|
||||||
- id: Outdoor
|
- device_id: waschkueche_licht
|
||||||
|
title: Waschküche Licht
|
||||||
|
icon: 💡
|
||||||
|
rank: 340
|
||||||
|
|
||||||
|
- id: outdoor
|
||||||
name: Outdoor
|
name: Outdoor
|
||||||
devices:
|
devices:
|
||||||
- device_id: licht_terasse
|
- device_id: licht_terasse
|
||||||
@@ -324,7 +341,7 @@ rooms:
|
|||||||
title: Gartenlicht vorne
|
title: Gartenlicht vorne
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 291
|
rank: 291
|
||||||
- id: Garage
|
- id: garage
|
||||||
name: Garage
|
name: Garage
|
||||||
devices:
|
devices:
|
||||||
- device_id: power_relay_caroutlet
|
- device_id: power_relay_caroutlet
|
||||||
@@ -339,5 +356,18 @@ rooms:
|
|||||||
title: Messwerte
|
title: Messwerte
|
||||||
icon: 📊
|
icon: 📊
|
||||||
rank: 320
|
rank: 320
|
||||||
|
- id: keller
|
||||||
|
name: Keller
|
||||||
|
devices:
|
||||||
|
- device_id: keller_flur_licht
|
||||||
|
title: Keller Flur Licht
|
||||||
|
icon: 💡
|
||||||
|
rank: 330
|
||||||
|
- device_id: werkstatt_licht
|
||||||
|
title: Werkstatt Licht
|
||||||
|
icon: 💡
|
||||||
|
rank: 350
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user