6.0 KiB
6.0 KiB
MAX! (eQ-3) Thermostat Integration
Overview
This document describes the integration of MAX! (eQ-3) thermostats via Homegear into the home automation system.
Protocol Characteristics
MAX! thermostats use a simple integer-based protocol (not JSON):
- SET messages: Plain integer temperature value (e.g.,
22) - STATE messages: Plain integer temperature value (e.g.,
22) - Topics: Homegear MQTT format
MQTT Topics
SET Command:
homegear/instance1/set/<peerId>/<channel>/SET_TEMPERATURE
Payload: "22" (plain integer as string)
STATE Update:
homegear/instance1/plain/<peerId>/<channel>/SET_TEMPERATURE
Payload: "22" (plain integer as string)
Transformation Layer
The abstraction layer provides automatic transformation between the abstract home protocol and MAX! format.
Abstract → MAX! (SET)
Input (Abstract):
{
"mode": "heat",
"target": 22.5
}
Output (MAX!):
22
Transformation Rules:
- Extract
targettemperature - Convert float → integer (round to nearest)
- Return as plain string (no JSON)
- Ignore
modefield (MAX! always in heating mode)
MAX! → Abstract (STATE)
Input (MAX!):
22
Output (Abstract):
{
"target": 22.0,
"mode": "heat"
}
Transformation Rules:
- Parse plain string/integer value
- Convert to float
- Add default
mode: "heat"(MAX! always heating) - Wrap in abstract payload structure
Device Configuration
Example devices.yaml Entry
- device_id: "thermostat_wolfgang"
type: "thermostat"
cap_version: "thermostat@1.0.0"
technology: "max"
features:
mode: true
target: true
current: false # SET_TEMPERATURE doesn't report current temp
topics:
set: "homegear/instance1/set/39/1/SET_TEMPERATURE"
state: "homegear/instance1/plain/39/1/SET_TEMPERATURE"
metadata:
friendly_name: "Thermostat Wolfgang"
location: "Arbeitszimmer Wolfgang"
vendor: "eQ-3"
model: "MAX! Thermostat"
peer_id: "39"
channel: "1"
Configuration Notes
- technology: Must be set to
"max"to activate MAX! transformations - topics.set: Use Homegear's
/set/path with/SET_TEMPERATUREparameter - topics.state: Use Homegear's
/plain/path with/SET_TEMPERATUREparameter - features.current: Set to
false- SET_TEMPERATURE topic doesn't provide current temperature - metadata: Include
peer_idandchannelfor reference
Temperature Rounding
MAX! only supports integer temperatures. The system uses standard rounding:
| Abstract Input | MAX! Output |
|---|---|
| 20.4°C | 20 |
| 20.5°C | 20 |
| 20.6°C | 21 |
| 21.5°C | 22 |
| 22.5°C | 22 |
Python's round() function uses "banker's rounding" (round half to even).
Limitations
- No current temperature: SET_TEMPERATURE topic only reports target, not actual temperature
- No mode control: MAX! thermostats are always in heating mode
- Integer only: Temperature precision limited to 1°C steps
- No battery status: Not available via SET_TEMPERATURE topic
- No window detection: Not available via SET_TEMPERATURE topic
Testing
Test the transformation functions:
poetry run python /tmp/test_max_transform.py
Expected output:
✅ PASS: Float 22.5 -> Integer string
✅ PASS: Integer string -> Abstract dict
✅ PASS: Integer -> Abstract dict
✅ PASS: Rounding works correctly
🎉 All MAX! transformation tests passed!
Implementation Details
Files Modified
-
apps/abstraction/transformation.py
- Added
_transform_thermostat_max_to_vendor()- converts abstract → plain integer - Added
_transform_thermostat_max_to_abstract()- converts plain integer → abstract - Registered handlers in
TRANSFORM_HANDLERSregistry
- Added
-
apps/abstraction/main.py
- Modified
handle_abstract_set()to send plain string for MAX! devices (not JSON) - Modified message processing to handle plain text payloads from MAX! STATE topics
- Modified
Transformation Functions
def _transform_thermostat_max_to_vendor(payload: dict[str, Any]) -> str:
"""Convert {"target": 22.5} → "22" """
target_temp = payload.get("target", 21.0)
return str(int(round(target_temp)))
def _transform_thermostat_max_to_abstract(payload: str | int | float) -> dict[str, Any]:
"""Convert "22" → {"target": 22.0, "mode": "heat"} """
target_temp = float(payload)
return {"target": target_temp, "mode": "heat"}
Usage Example
Setting Temperature via API
curl -X POST http://localhost:8001/devices/thermostat_wolfgang/set \
-H "Content-Type: application/json" \
-d '{
"type": "thermostat",
"payload": {
"mode": "heat",
"target": 22.5
}
}'
Flow:
- API receives abstract payload:
{"mode": "heat", "target": 22.5} - Abstraction transforms to MAX!:
"22" - Publishes to:
homegear/instance1/set/39/1/SET_TEMPERATUREwith payload22
Receiving State Updates
Homegear publishes:
Topic: homegear/instance1/plain/39/1/SET_TEMPERATURE
Payload: 22
Flow:
- Abstraction receives plain text:
"22" - Transforms to abstract:
{"target": 22.0, "mode": "heat"} - Publishes to:
home/thermostat/thermostat_wolfgang/state - Publishes to Redis:
ui:updateschannel for real-time UI updates
Future Enhancements
Potential improvements for better MAX! integration:
- Current Temperature: Subscribe to separate Homegear topic for actual temperature
- Battery Status: Subscribe to LOWBAT or battery level topics
- Valve Position: Monitor actual valve opening percentage
- Window Detection: Subscribe to window open detection status
- Mode Control: Support comfort/eco temperature presets