Compare commits
2 Commits
window_con
...
temperatur
| Author | SHA1 | Date | |
|---|---|---|---|
|
86d1933c1f
|
|||
|
9458381593
|
@@ -15,7 +15,7 @@ import uuid
|
|||||||
from aiomqtt import Client
|
from aiomqtt import Client
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from packages.home_capabilities import LightState, ThermostatState, ContactState
|
from packages.home_capabilities import LightState, ThermostatState, ContactState, TempHumidityState
|
||||||
from apps.abstraction.transformation import (
|
from apps.abstraction.transformation import (
|
||||||
transform_abstract_to_vendor,
|
transform_abstract_to_vendor,
|
||||||
transform_vendor_to_abstract
|
transform_vendor_to_abstract
|
||||||
@@ -222,12 +222,16 @@ async def handle_vendor_state(
|
|||||||
elif device_type in {"contact", "contact_sensor"}:
|
elif device_type in {"contact", "contact_sensor"}:
|
||||||
# Validate contact sensor state
|
# Validate contact sensor state
|
||||||
ContactState.model_validate(abstract_payload)
|
ContactState.model_validate(abstract_payload)
|
||||||
|
elif device_type in {"temp_humidity", "temp_humidity_sensor"}:
|
||||||
|
# Validate temperature & humidity sensor state
|
||||||
|
TempHumidityState.model_validate(abstract_payload)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
logger.error(f"Validation failed for {device_type} STATE {device_id}: {e}")
|
logger.error(f"Validation failed for {device_type} STATE {device_id}: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Normalize device type for topic (use 'contact' for both 'contact' and 'contact_sensor')
|
# Normalize device type for topic (use 'contact' for both 'contact' and 'contact_sensor')
|
||||||
topic_type = "contact" if device_type in {"contact", "contact_sensor"} else device_type
|
topic_type = "contact" if device_type in {"contact", "contact_sensor"} else device_type
|
||||||
|
topic_type = "temp_humidity" if device_type in {"temp_humidity", "temp_humidity_sensor"} else topic_type
|
||||||
|
|
||||||
# Publish to abstract state topic (retained)
|
# Publish to abstract state topic (retained)
|
||||||
abstract_topic = f"home/{topic_type}/{device_id}/state"
|
abstract_topic = f"home/{topic_type}/{device_id}/state"
|
||||||
|
|||||||
@@ -265,6 +265,48 @@ def _transform_contact_sensor_max_to_abstract(payload: str | bool | dict[str, An
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HANDLER FUNCTIONS: temp_humidity_sensor - zigbee2mqtt technology
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def _transform_temp_humidity_sensor_zigbee2mqtt_to_vendor(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Transform abstract temp/humidity sensor payload to zigbee2mqtt format.
|
||||||
|
|
||||||
|
Temp/humidity sensors are read-only, so this should not be called for SET commands.
|
||||||
|
Returns payload as-is for compatibility.
|
||||||
|
"""
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def _transform_temp_humidity_sensor_zigbee2mqtt_to_abstract(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Transform zigbee2mqtt temp/humidity sensor payload to abstract format.
|
||||||
|
|
||||||
|
Passthrough - zigbee2mqtt provides temperature, humidity, battery, linkquality directly.
|
||||||
|
"""
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# HANDLER FUNCTIONS: temp_humidity_sensor - MAX! technology
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def _transform_temp_humidity_sensor_max_to_vendor(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Transform abstract temp/humidity sensor payload to MAX! format.
|
||||||
|
|
||||||
|
Temp/humidity sensors are read-only, so this should not be called for SET commands.
|
||||||
|
Returns payload as-is for compatibility.
|
||||||
|
"""
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def _transform_temp_humidity_sensor_max_to_abstract(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Transform MAX! temp/humidity sensor payload to abstract format.
|
||||||
|
|
||||||
|
Passthrough - MAX! provides temperature, humidity, battery directly.
|
||||||
|
"""
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# HANDLER FUNCTIONS: max technology (Homegear MAX!)
|
# HANDLER FUNCTIONS: max technology (Homegear MAX!)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -368,6 +410,16 @@ TRANSFORM_HANDLERS: dict[tuple[str, str, str], TransformHandler] = {
|
|||||||
("contact", "zigbee2mqtt", "to_abstract"): _transform_contact_sensor_zigbee2mqtt_to_abstract,
|
("contact", "zigbee2mqtt", "to_abstract"): _transform_contact_sensor_zigbee2mqtt_to_abstract,
|
||||||
("contact", "max", "to_vendor"): _transform_contact_sensor_max_to_vendor,
|
("contact", "max", "to_vendor"): _transform_contact_sensor_max_to_vendor,
|
||||||
("contact", "max", "to_abstract"): _transform_contact_sensor_max_to_abstract,
|
("contact", "max", "to_abstract"): _transform_contact_sensor_max_to_abstract,
|
||||||
|
|
||||||
|
# Temperature & humidity sensor transformations (support both type aliases)
|
||||||
|
("temp_humidity_sensor", "zigbee2mqtt", "to_vendor"): _transform_temp_humidity_sensor_zigbee2mqtt_to_vendor,
|
||||||
|
("temp_humidity_sensor", "zigbee2mqtt", "to_abstract"): _transform_temp_humidity_sensor_zigbee2mqtt_to_abstract,
|
||||||
|
("temp_humidity_sensor", "max", "to_vendor"): _transform_temp_humidity_sensor_max_to_vendor,
|
||||||
|
("temp_humidity_sensor", "max", "to_abstract"): _transform_temp_humidity_sensor_max_to_abstract,
|
||||||
|
("temp_humidity", "zigbee2mqtt", "to_vendor"): _transform_temp_humidity_sensor_zigbee2mqtt_to_vendor,
|
||||||
|
("temp_humidity", "zigbee2mqtt", "to_abstract"): _transform_temp_humidity_sensor_zigbee2mqtt_to_abstract,
|
||||||
|
("temp_humidity", "max", "to_vendor"): _transform_temp_humidity_sensor_max_to_vendor,
|
||||||
|
("temp_humidity", "max", "to_abstract"): _transform_temp_humidity_sensor_max_to_abstract,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ from packages.home_capabilities import (
|
|||||||
LIGHT_VERSION,
|
LIGHT_VERSION,
|
||||||
THERMOSTAT_VERSION,
|
THERMOSTAT_VERSION,
|
||||||
CONTACT_SENSOR_VERSION,
|
CONTACT_SENSOR_VERSION,
|
||||||
|
TEMP_HUMIDITY_SENSOR_VERSION,
|
||||||
LightState,
|
LightState,
|
||||||
ThermostatState,
|
ThermostatState,
|
||||||
ContactState
|
ContactState,
|
||||||
|
TempHumidityState
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -145,7 +147,8 @@ async def spec() -> dict[str, dict[str, str]]:
|
|||||||
"capabilities": {
|
"capabilities": {
|
||||||
"light": LIGHT_VERSION,
|
"light": LIGHT_VERSION,
|
||||||
"thermostat": THERMOSTAT_VERSION,
|
"thermostat": THERMOSTAT_VERSION,
|
||||||
"contact": CONTACT_SENSOR_VERSION
|
"contact": CONTACT_SENSOR_VERSION,
|
||||||
|
"temp_humidity": TEMP_HUMIDITY_SENSOR_VERSION
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +380,12 @@ async def set_device(device_id: str, request: SetDeviceRequest) -> dict[str, str
|
|||||||
status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
|
status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
|
||||||
detail="Contact sensors are read-only devices"
|
detail="Contact sensors are read-only devices"
|
||||||
)
|
)
|
||||||
|
elif request.type in {"temp_humidity", "temp_humidity_sensor"}:
|
||||||
|
# Temperature & humidity sensors are read-only
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
|
||||||
|
detail="Temperature & humidity sensors are read-only devices"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||||
|
|||||||
@@ -426,6 +426,58 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Temperature & Humidity Sensor Styles */
|
||||||
|
.temp-humidity-display {
|
||||||
|
padding: 1rem;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border-radius: 12px;
|
||||||
|
color: white;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.75rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-row:not(:last-child) {
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-value {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-battery {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-humidity-info {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.events {
|
.events {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
background: white;
|
background: white;
|
||||||
@@ -607,6 +659,28 @@
|
|||||||
🔒 Nur-Lesen Gerät • Keine Steuerung möglich
|
🔒 Nur-Lesen Gerät • Keine Steuerung möglich
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% elif device.type == "temp_humidity" or device.type == "temp_humidity_sensor" %}
|
||||||
|
<div class="temp-humidity-display">
|
||||||
|
<div class="temp-humidity-row">
|
||||||
|
<span class="temp-humidity-label">🌡️ Temperatur:</span>
|
||||||
|
<span class="temp-humidity-value" id="th-{{ device.device_id }}-t">--</span>
|
||||||
|
<span style="font-size: 1.25rem; font-weight: 600;">°C</span>
|
||||||
|
</div>
|
||||||
|
<div class="temp-humidity-row">
|
||||||
|
<span class="temp-humidity-label">💧 Luftfeuchte:</span>
|
||||||
|
<span class="temp-humidity-value" id="th-{{ device.device_id }}-h">--</span>
|
||||||
|
<span style="font-size: 1.25rem; font-weight: 600;">%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="temp-humidity-battery" id="th-{{ device.device_id }}-battery" style="display: none;">
|
||||||
|
🔋 <span id="th-{{ device.device_id }}-battery-value">--</span>%
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="temp-humidity-info">
|
||||||
|
🔒 Nur-Lesen Gerät • Keine Steuerung möglich
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -922,6 +996,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update temperature & humidity sensor UI
|
||||||
|
function updateTempHumidityUI(deviceId, payload) {
|
||||||
|
const tempSpan = document.getElementById(`th-${deviceId}-t`);
|
||||||
|
const humiditySpan = document.getElementById(`th-${deviceId}-h`);
|
||||||
|
const batteryDiv = document.getElementById(`th-${deviceId}-battery`);
|
||||||
|
const batteryValueSpan = document.getElementById(`th-${deviceId}-battery-value`);
|
||||||
|
|
||||||
|
if (!tempSpan || !humiditySpan) {
|
||||||
|
console.warn(`No temp/humidity elements found for device ${deviceId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update temperature (rounded to 1 decimal)
|
||||||
|
if (payload.temperature !== undefined && payload.temperature !== null) {
|
||||||
|
tempSpan.textContent = payload.temperature.toFixed(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update humidity (rounded to 0-1 decimals)
|
||||||
|
if (payload.humidity !== undefined && payload.humidity !== null) {
|
||||||
|
// Round to 1 decimal if has decimals, otherwise integer
|
||||||
|
const humidity = payload.humidity;
|
||||||
|
humiditySpan.textContent = (humidity % 1 === 0) ? humidity.toFixed(0) : humidity.toFixed(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update battery if present
|
||||||
|
if (payload.battery !== undefined && payload.battery !== null && batteryDiv && batteryValueSpan) {
|
||||||
|
batteryValueSpan.textContent = payload.battery;
|
||||||
|
batteryDiv.style.display = 'block';
|
||||||
|
} else if (batteryDiv) {
|
||||||
|
batteryDiv.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add event to list
|
// Add event to list
|
||||||
function addEvent(event) {
|
function addEvent(event) {
|
||||||
const eventList = document.getElementById('event-list');
|
const eventList = document.getElementById('event-list');
|
||||||
@@ -992,6 +1099,11 @@
|
|||||||
if (data.payload.contact !== undefined) {
|
if (data.payload.contact !== undefined) {
|
||||||
updateContactUI(data.device_id, data.payload.contact);
|
updateContactUI(data.device_id, data.payload.contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it's a temp/humidity sensor
|
||||||
|
if (data.payload.temperature !== undefined || data.payload.humidity !== undefined) {
|
||||||
|
updateTempHumidityUI(data.device_id, data.payload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1113,6 +1225,9 @@
|
|||||||
} else if (state.contact !== undefined) {
|
} else if (state.contact !== undefined) {
|
||||||
// It's a contact sensor
|
// It's a contact sensor
|
||||||
updateContactUI(deviceId, state.contact);
|
updateContactUI(deviceId, state.contact);
|
||||||
|
} else if (state.temperature !== undefined || state.humidity !== undefined) {
|
||||||
|
// It's a temp/humidity sensor
|
||||||
|
updateTempHumidityUI(deviceId, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -639,4 +639,85 @@ devices:
|
|||||||
topics:
|
topics:
|
||||||
state: homegear/instance1/plain/44/1/STATE
|
state: homegear/instance1/plain/44/1/STATE
|
||||||
features: {}
|
features: {}
|
||||||
|
- device_id: sensor_schlafzimmer
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d00043292dc
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_wohnzimmer
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d0008975707
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_kueche
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d00083299bb
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_arbeitszimmer_patty
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d0003f052b7
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_arbeitszimmer_wolfgang
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d000543fb99
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_bad_oben
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d00093e8987
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_bad_unten
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d00093e662a
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_flur
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d000836ccc6
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_waschkueche
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d000449f3bc
|
||||||
|
features: {}
|
||||||
|
- device_id: sensor_sportzimmer
|
||||||
|
type: temp_humidity_sensor
|
||||||
|
name: Temperatur & Luftfeuchte
|
||||||
|
cap_version: temp_humidity_sensor@1.0.0
|
||||||
|
technology: zigbee2mqtt
|
||||||
|
topics:
|
||||||
|
state: zigbee2mqtt/0x00158d0009421422
|
||||||
|
features: {}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ rooms:
|
|||||||
title: Kontakt Straße
|
title: Kontakt Straße
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 46
|
rank: 46
|
||||||
|
- device_id: sensor_schlafzimmer
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 47
|
||||||
- name: Esszimmer
|
- name: Esszimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: deckenlampe_esszimmer
|
- device_id: deckenlampe_esszimmer
|
||||||
@@ -89,6 +93,10 @@ rooms:
|
|||||||
title: Kontakt Garten links
|
title: Kontakt Garten links
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 137
|
rank: 137
|
||||||
|
- device_id: sensor_wohnzimmer
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 138
|
||||||
- name: Küche
|
- name: Küche
|
||||||
devices:
|
devices:
|
||||||
- device_id: kueche_deckenlampe
|
- device_id: kueche_deckenlampe
|
||||||
@@ -115,6 +123,10 @@ rooms:
|
|||||||
title: Kontakt Straße links
|
title: Kontakt Straße links
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 154
|
rank: 154
|
||||||
|
- device_id: sensor_kueche
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 155
|
||||||
- name: Arbeitszimmer Patty
|
- name: Arbeitszimmer Patty
|
||||||
devices:
|
devices:
|
||||||
- device_id: leselampe_patty
|
- device_id: leselampe_patty
|
||||||
@@ -145,6 +157,10 @@ rooms:
|
|||||||
title: Kontakt Straße
|
title: Kontakt Straße
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 188
|
rank: 188
|
||||||
|
- device_id: sensor_arbeitszimmer_patty
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 189
|
||||||
- name: Arbeitszimmer Wolfgang
|
- name: Arbeitszimmer Wolfgang
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_wolfgang
|
- device_id: thermostat_wolfgang
|
||||||
@@ -159,6 +175,10 @@ rooms:
|
|||||||
title: Kontakt Garten
|
title: Kontakt Garten
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 201
|
rank: 201
|
||||||
|
- device_id: sensor_arbeitszimmer_wolfgang
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 202
|
||||||
- name: Flur
|
- name: Flur
|
||||||
devices:
|
devices:
|
||||||
- device_id: deckenlampe_flur_oben
|
- device_id: deckenlampe_flur_oben
|
||||||
@@ -173,6 +193,10 @@ rooms:
|
|||||||
title: Licht Flur oben am Spiegel
|
title: Licht Flur oben am Spiegel
|
||||||
icon: 💡
|
icon: 💡
|
||||||
rank: 230
|
rank: 230
|
||||||
|
- device_id: sensor_flur
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 235
|
||||||
- name: Sportzimmer
|
- name: Sportzimmer
|
||||||
devices:
|
devices:
|
||||||
- device_id: sportlicht_regal
|
- device_id: sportlicht_regal
|
||||||
@@ -187,6 +211,10 @@ rooms:
|
|||||||
title: Sportlicht am Fernseher, Studierzimmer
|
title: Sportlicht am Fernseher, Studierzimmer
|
||||||
icon: 🏃
|
icon: 🏃
|
||||||
rank: 260
|
rank: 260
|
||||||
|
- device_id: sensor_sportzimmer
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 265
|
||||||
- name: Bad Oben
|
- name: Bad Oben
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_bad_oben
|
- device_id: thermostat_bad_oben
|
||||||
@@ -197,6 +225,10 @@ rooms:
|
|||||||
title: Kontakt Straße
|
title: Kontakt Straße
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 271
|
rank: 271
|
||||||
|
- device_id: sensor_bad_oben
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 272
|
||||||
- name: Bad Unten
|
- name: Bad Unten
|
||||||
devices:
|
devices:
|
||||||
- device_id: thermostat_bad_unten
|
- device_id: thermostat_bad_unten
|
||||||
@@ -207,4 +239,14 @@ rooms:
|
|||||||
title: Kontakt Straße
|
title: Kontakt Straße
|
||||||
icon: 🪟
|
icon: 🪟
|
||||||
rank: 281
|
rank: 281
|
||||||
|
- device_id: sensor_bad_unten
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 282
|
||||||
|
- name: Waschküche
|
||||||
|
devices:
|
||||||
|
- device_id: sensor_waschkueche
|
||||||
|
title: Temperatur & Luftfeuchte
|
||||||
|
icon: 🌡️
|
||||||
|
rank: 290
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,31 @@
|
|||||||
Schlafzimmer
|
Schlafzimmer
|
||||||
52 Straße
|
0x00158d00043292dc
|
||||||
|
|
||||||
|
|
||||||
Esszimmer
|
Esszimmer
|
||||||
26 Straße rechts
|
|
||||||
27 Straße links
|
|
||||||
|
|
||||||
Wohnzimmer
|
Wohnzimmer
|
||||||
28 Garten rechts
|
0x00158d0008975707
|
||||||
29 Garten links
|
|
||||||
|
|
||||||
Küche
|
Küche
|
||||||
0x00158d008b332785 Garten Fenster
|
0x00158d00083299bb
|
||||||
0x00158d008b332788 Garten Tür
|
|
||||||
0x00158d008b151803 Straße rechts
|
|
||||||
0x00158d008b331d0b Straße links
|
|
||||||
|
|
||||||
|
|
||||||
Arbeitszimmer Patty
|
Arbeitszimmer Patty
|
||||||
18 Garten rechts
|
0x00158d0003f052b7
|
||||||
22 Garten links
|
|
||||||
0x00158d000af457cf Straße
|
|
||||||
|
|
||||||
Arbeitszimmer Wolfgang
|
Arbeitszimmer Wolfgang
|
||||||
0x00158d008b3328da Garten
|
0x00158d000543fb99
|
||||||
|
|
||||||
|
|
||||||
Bad Oben
|
Bad Oben
|
||||||
0x00158d008b333aec Straße
|
0x00158d00093e8987
|
||||||
|
|
||||||
Bad Unten
|
Bad Unten
|
||||||
44 Straße
|
0x00158d00093e662a
|
||||||
|
|
||||||
|
Flur
|
||||||
|
0x00158d000836ccc6
|
||||||
|
|
||||||
|
Waschküche
|
||||||
|
0x00158d000449f3bc
|
||||||
|
|
||||||
|
Sportzimmer
|
||||||
|
0x00158d0009421422
|
||||||
@@ -6,6 +6,8 @@ from packages.home_capabilities.thermostat import CAP_VERSION as THERMOSTAT_VERS
|
|||||||
from packages.home_capabilities.thermostat import ThermostatState
|
from packages.home_capabilities.thermostat import ThermostatState
|
||||||
from packages.home_capabilities.contact_sensor import CAP_VERSION as CONTACT_SENSOR_VERSION
|
from packages.home_capabilities.contact_sensor import CAP_VERSION as CONTACT_SENSOR_VERSION
|
||||||
from packages.home_capabilities.contact_sensor import ContactState
|
from packages.home_capabilities.contact_sensor import ContactState
|
||||||
|
from packages.home_capabilities.temp_humidity_sensor import CAP_VERSION as TEMP_HUMIDITY_SENSOR_VERSION
|
||||||
|
from packages.home_capabilities.temp_humidity_sensor import TempHumidityState
|
||||||
from packages.home_capabilities.layout import DeviceTile, Room, UiLayout, load_layout
|
from packages.home_capabilities.layout import DeviceTile, Room, UiLayout, load_layout
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@@ -15,6 +17,8 @@ __all__ = [
|
|||||||
"THERMOSTAT_VERSION",
|
"THERMOSTAT_VERSION",
|
||||||
"ContactState",
|
"ContactState",
|
||||||
"CONTACT_SENSOR_VERSION",
|
"CONTACT_SENSOR_VERSION",
|
||||||
|
"TempHumidityState",
|
||||||
|
"TEMP_HUMIDITY_SENSOR_VERSION",
|
||||||
"DeviceTile",
|
"DeviceTile",
|
||||||
"Room",
|
"Room",
|
||||||
"UiLayout",
|
"UiLayout",
|
||||||
|
|||||||
37
packages/home_capabilities/temp_humidity_sensor.py
Normal file
37
packages/home_capabilities/temp_humidity_sensor.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
Temperature & Humidity Sensor Capability - temp_humidity_sensor@1.0.0
|
||||||
|
|
||||||
|
Read-only sensor for temperature and humidity measurements.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class TempHumidityState(BaseModel):
|
||||||
|
"""
|
||||||
|
State model for temperature & humidity sensors.
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
- temperature: Temperature in degrees Celsius
|
||||||
|
- humidity: Relative humidity in percent
|
||||||
|
|
||||||
|
Optional fields:
|
||||||
|
- battery: Battery level 0-100%
|
||||||
|
- linkquality: Signal quality indicator
|
||||||
|
- voltage: Battery voltage in mV
|
||||||
|
- ts: Timestamp of measurement
|
||||||
|
"""
|
||||||
|
temperature: float = Field(..., description="Temperature in degrees Celsius")
|
||||||
|
humidity: float = Field(..., description="Relative humidity in percent (0-100)")
|
||||||
|
battery: Annotated[int, Field(ge=0, le=100)] | None = None
|
||||||
|
linkquality: int | None = None
|
||||||
|
voltage: int | None = None
|
||||||
|
ts: datetime | None = None
|
||||||
|
|
||||||
|
|
||||||
|
# Capability metadata
|
||||||
|
CAP_VERSION = "temp_humidity_sensor@1.0.0"
|
||||||
|
DISPLAY_NAME = "Temperature & Humidity Sensor"
|
||||||
Reference in New Issue
Block a user