API Issues and Workarounds - delize/home-assistant-loggamera-integration GitHub Wiki
API Version: Loggamera Platform API v2
Last Updated: 2025-01-18
Integration Version: 0.7.3+
This document catalogs known issues, inconsistencies, and undocumented behaviors in the Loggamera Platform API v2, along with the workarounds implemented in the Home Assistant integration.
Issue Category | Impact | Workaround Status |
---|---|---|
Spelling Errors | Display names | ✅ Fixed in integration |
Missing Endpoints | HeatMeter support | ✅ Fallback implemented |
Response Format | Error handling | ✅ Normalized in integration |
Authentication | Non-standard auth | ✅ Implemented correctly |
Endpoint Availability | Device support | ✅ Fallback mechanisms |
Data Types | Type conversion | ✅ Auto-conversion |
SSL/TLS Issues | Connectivity | ✅ Certificate management |
Update Frequency | Data freshness | |
Data Pull Issues | Missing/empty data | 🔍 Under investigation |
Organization Access | Complex hierarchy | ✅ State management |
Error Handling | Inconsistent errors | ✅ Error normalization |
Issue: API consistently returns misspelled "Voltate" in sensor names.
Affected: ChargingStation devices via RawData endpoint Sensor IDs: 544426, 544427, 544428
API Response:
{
"ClearTextName": "Voltate (Phase 1)",
"Name": "544426"
}
Expected: "Voltage (Phase 1)"
✅ Integration Fix: Automatic spelling correction in sensor display names
# Sensor name correction in sensor.py
if "Voltate" in clear_name:
clear_name = clear_name.replace("Voltate", "Voltage")
Issue: API returns "Signal-Noice relation (Snr)" instead of proper "Signal-Noise ratio (SNR)".
Affected: RoomSensor devices via RawData endpoint Sensor ID: 543837
✅ Integration Fix: Terminology correction for technical accuracy
if "Signal-Noice" in clear_name:
clear_name = clear_name.replace("Signal-Noice", "Signal-Noise")
Issue: Despite HeatMeter being a supported device type, there is no dedicated /HeatMeter
endpoint.
Expected: POST /api/v2/HeatMeter
endpoint (similar to PowerMeter, WaterMeter)
Actual: Returns "invalid endpoint" error
Impact: HeatMeter devices cannot use optimized device-specific endpoints
✅ Integration Solution:
-
Primary: Use
/RawData
endpoint for all HeatMeter data -
Fallback: Use
/GenericDevice
for alarm information - Special mapping: Dedicated sensor mappings for HeatMeter RawData IDs (544310-544324)
# HeatMeter handling in api.py
if device_type == "HeatMeter":
# HeatMeter has no dedicated endpoint - use RawData directly
primary_endpoint = None
Issue: Some endpoints return HTTP 200 with completely empty response bodies instead of proper JSON error responses.
Affected: Various device-specific endpoints when device type is unsupported
Expected: JSON error response or HTTP error status Actual: Empty string response body
✅ Integration Fix: Pre-parse empty response detection
# Handle endpoints that return no response body
if not response.text.strip():
result = {"Data": None, "Error": None}
else:
result = response.json()
Issue: Error messages returned in different formats across endpoints.
Format 1 (Most endpoints):
{
"Error": "error message string"
}
Format 2 (Some endpoints):
{
"Error": {
"Message": "error message string"
}
}
✅ Integration Fix: Unified error parsing
# Handle both error format types
if "Error" in result and result["Error"] is not None:
if isinstance(result["Error"], dict) and "Message" in result["Error"]:
error_message = result["Error"]["Message"]
else:
error_message = str(result["Error"])
Issue: ValueType
field is often null in RawData responses rather than meaningful values.
Impact: Cannot determine sensor data type directly from API metadata
✅ Integration Fix: Intelligent type inference
# Infer sensor types from UnitType and Value content
def _infer_sensor_type(self, value_data):
unit_type = value_data.get("UnitType", "").lower()
if unit_type in ["°c", "celsius"]:
return "temperature"
elif unit_type in ["%", "percent"]:
return "humidity" if "humidity" in name.lower() else "generic"
# ... additional inference logic
Issue: API requires API key in JSON request body rather than standard HTTP Authorization header.
Standard Practice: Authorization: Bearer <api_key>
header
Loggamera API: "ApiKey": "<api_key>"
in request body
✅ Integration Implementation: Correct non-standard authentication
# Always include the API key in request body
if "ApiKey" not in data:
data["ApiKey"] = self.api_key
Issue: Not all endpoints work with all device types, but this is undocumented.
Examples:
- PowerMeter devices: PowerMeter endpoint works
- HeatMeter devices: No dedicated endpoint, must use RawData
- Some devices: Capabilities endpoint not available
✅ Integration Solution: Endpoint cascading with caching
# Intelligent endpoint fallback system
def _get_primary_endpoint_for_device(self, device_id, device_type):
# 1. Try device-specific endpoint
if primary_endpoint and not self._endpoint_cache.get(primary_endpoint, False):
try:
return self._make_request(primary_endpoint, {"DeviceId": device_id})
except LoggameraAPIError:
self._endpoint_cache[primary_endpoint] = False
# 2. Fallback to generic endpoints
for endpoint in [API_ENDPOINT_RAW_DATA, API_ENDPOINT_GENERIC_DEVICE]:
# Try each fallback endpoint...
Issue: API returns "invalid endpoint" for both unsupported endpoints and permission issues.
Impact: Cannot distinguish between true unavailability and permissions
✅ Integration Solution: Endpoint availability caching
# Cache invalid endpoints to avoid repeated failures
if error_message == "invalid endpoint":
self._endpoint_cache[endpoint] = False
raise LoggameraAPIError(f"API error: {error_message}")
Issue: API returns both lowercase and uppercase variants for the same unit type.
Examples:
-
"ConsumedTotalInm3"
(lowercase m3) -
"ConsumedTotalInM3"
(uppercase M3)
✅ Integration Fix: Case-insensitive unit mapping
# Handle both case variants
if any(unit in sensor_name.lower() for unit in ["inkwh", "kwh"]):
return "energy"
elif any(unit in sensor_name.lower() for unit in ["inm3", "m3", "m³"]):
return "water"
Issue: Numeric values sometimes returned as strings, sometimes as numbers.
✅ Integration Fix: Automatic type conversion
def _convert_value(self, value):
"""Convert string numbers to appropriate numeric types."""
if isinstance(value, str):
try:
if '.' in value:
return float(value)
else:
return int(value)
except ValueError:
return value
return value
Issue: SSL certificate verification frequently fails in various environments, especially Docker.
Common Errors:
CERTIFICATE_VERIFY_FAILED
WRONG_VERSION_NUMBER
- Missing CA certificates
✅ Integration Solution: Explicit certificate management
# Explicit certificate path using certifi
self.session.verify = certifi.where()
Additional Tools: tools/diagnose_tls.sh
for automatic certificate diagnosis and fixes
Issue: PowerMeter endpoint data only updates approximately every 30 minutes regardless of polling frequency.
Impact: More frequent polling doesn't yield more current data
Integration Response:
- Default scan interval set to 20 minutes (1200 seconds)
- Documentation explains the limitation
- Monitoring tools available to analyze actual update patterns
# Default optimized for PowerMeter update frequency
DEFAULT_SCAN_INTERVAL = 1200 # 20 minutes
Issue: Periodic instances where API endpoints return no data or empty responses despite devices being active and accessible.
Symptoms:
- API returns empty "Data" arrays when data should be present
- Intermittent data gaps in otherwise functional device feeds
- Affects different environments inconsistently (e.g., test vs production)
- Timing patterns suggest potential server-side processing issues
Observed Patterns:
- Time-based: Often occurs during specific time windows (e.g., 4 AM processing cycles)
- Environment-specific: May affect test environments while production remains stable
- Device-agnostic: Can affect multiple device types simultaneously
- Temporary: Usually resolves within normal update cycles (15-30 minutes)
Example Scenarios:
- Organization endpoint returns empty device lists when devices exist
- Device endpoints return
{"Data": {"Values": []}}
despite recent activity - RawData endpoints intermittently unavailable for active devices
🔍 Current Investigation Status:
- Root cause analysis: Ongoing investigation into API backend processing patterns
- Monitoring implementation: Adding timestamp logging to identify specific failure windows
- Environment correlation: Comparing test vs production environment behaviors
- Retry strategy evaluation: Assessing optimal retry intervals for these scenarios
- Retry logic with exponential backoff already implemented
- Circuit breaker prevents excessive retry attempts
- Integration gracefully handles empty responses without crashing
- Error logging captures instances for pattern analysis
Integration Response:
# Enhanced logging for data pull issue analysis
if not data_values or len(data_values) == 0:
self._logger.warning(
"Empty data response for device %s at %s - investigating timing patterns",
device_id,
datetime.now().isoformat()
)
📈 Investigation Areas:
- API Server Processing: Backend data aggregation timing and caching
- Load Balancing: Request routing consistency across API instances
- Database Sync: Data consistency between API backend databases
- Time Zone Handling: UTC vs local time processing in API responses
- Caching Layers: API response caching invalidation patterns
Next Steps:
- Continued monitoring and data collection
- Have added extensive data logging for this issue
- Correlation analysis with API vendor
- Enhanced diagnostic tools for real-time detection
- Potential API polling strategy adjustments based on findings
Issue: Accessing devices in child organizations requires temporarily switching organization context.
Required Process:
- Store original organization ID
- Switch to child organization ID
- Make device request
- Restore original organization ID
✅ Integration Solution: Careful state management
# Temporary organization context switching
original_org_id = self.api.organization_id
try:
self.api.organization_id = child_org_id
child_devices = await self.hass.async_add_executor_job(self.api.get_devices)
# Process child organization devices
finally:
self.api.organization_id = original_org_id
Issue: Capabilities endpoint may not be available for all devices but returns "invalid endpoint" instead of empty capabilities.
Expected: Empty capabilities response Actual: "invalid endpoint" error
✅ Integration Solution: Graceful degradation
try:
return self._make_request(API_ENDPOINT_CAPABILITIES, {"DeviceId": device_id})
except LoggameraAPIError as e:
if "invalid endpoint" in str(e):
return {
"Data": {"ReadCapabilities": [], "WriteCapabilities": []},
"Error": None,
}
else:
raise
Issue: Scenarios endpoint may not be available for all organizations.
Expected: Empty scenarios list when none exist Actual: "invalid endpoint" error for organizations without scenario support
✅ Integration Solution: Empty list fallback
try:
return self._make_request(API_ENDPOINT_SCENARIOS, {"OrganizationId": self.organization_id})
except LoggameraAPIError as e:
if "invalid endpoint" in str(e):
return {"Data": {"Scenarios": []}, "Error": None}
else:
raise
The Home Assistant integration implements comprehensive workarounds for these API issues:
- ✅ Endpoint cascading: Try primary → RawData → GenericDevice
- ✅ Endpoint caching: Remember invalid endpoints to avoid repeated failures
- ✅ Error normalization: Handle multiple error response formats
- ✅ Graceful degradation: Return empty responses instead of errors when appropriate
- ✅ Spelling correction: Fix API typos in display names
- ✅ Type conversion: Convert string numbers to appropriate numeric types
- ✅ Unit standardization: Handle case variations in unit names
- ✅ Value sanitization: Clean and validate sensor values
- ✅ SSL handling: Explicit certificate management with diagnostic tools
- ✅ Timeout handling: Reasonable timeouts with exponential backoff retry logic
- ✅ State management: Careful organization context switching
- ✅ Circuit breaker: Prevent repeated calls to failing endpoints
- ✅ Exponential backoff: 15s → 30s → 60s retry delays
- ✅ Circuit breaker: Opens after 6 failures, 5-minute timeout
- ✅ Error classification: Different retry strategies for different error types
- ✅ Network resilience: Handle connectivity and timeout issues
- Standardize Error Responses: Use consistent error message format across all endpoints
- Fix Spelling Errors: Correct "Voltate" → "Voltage" and "Signal-Noice" → "Signal-Noise"
-
Add HeatMeter Endpoint: Implement dedicated
/HeatMeter
endpoint - Document Endpoint Support: Clearly specify which endpoints work with which device types
- Improve Authentication: Support standard Authorization headers
- Consistent Data Types: Return numeric values as numbers, not strings
- Update Frequency Documentation: Document actual update intervals for each endpoint
- Graceful Degradation: Return empty arrays instead of "invalid endpoint" errors
- SSL Certificate Improvements: Ensure certificate chain compatibility across environments
- Organization Hierarchy: Support accessing child organization devices in single requests
The integration includes comprehensive diagnostic tools to test these workarounds:
- API Explorer: Test specific endpoints and responses
- Organization Mapper: Validate endpoint availability across devices
- Sensor Mapping Validation: Test data normalization and type conversion
- SSL Diagnostics: Validate certificate handling
Note: This documentation reflects integration development experience and testing. API behavior may change in future versions. Always consult official Loggamera API documentation for authoritative information.