solar_of_things/
├── __init__.py # Integration setup and coordinator
├── api.py # API client for Solar of Things
├── config_flow.py # Configuration UI flow
├── const.py # Constants and sensor definitions
├── manifest.json # Integration metadata
├── sensor.py # Sensor entity definitions
├── strings.json # UI strings
├── translations/ # Localization files
│ └── en.json
├── tests/ # Unit tests
│ ├── conftest.py
│ └── test_config_flow.py
├── README.md # User documentation
├── INSTALLATION.md # Installation guide
├── EXAMPLES.md # Configuration examples
├── CHANGELOG.md # Version history
└── LICENSE # MIT License
api.py)The SolarOfThingsAPI class handles all communication with the Solar of Things API:
/api/attribute/keys/history/v1/api/stateAttributeSummary/category/yearlyfetch_latest_data(): Retrieves the last hour of time-series datafetch_monthly_summary(): Gets current month statisticstest_connection(): Validates credentialsKey Features:
__init__.py)The SolarOfThingsDataUpdateCoordinator manages data updates:
async_add_executor_jobUpdateFailed exception for coordinator retry logicData Structure:
{
"time_series": {sensor_key: value, ...},
"monthly": {monthly_key: value, ...},
"station_id": "...",
"device_id": "..."
}
sensor.py)Two sensor classes:
SolarOfThingsSensor (real-time):
coordinator.data["time_series"]SolarOfThingsMonthlySensor (monthly stats):
coordinator.data["monthly"]config_flow.py)UI-based configuration:
{station_id}_{device_id} to prevent duplicatesURL: https://solar.siseli.com/api/attribute/keys/history/v1
Method: POST
Headers:
{
"IOT-Token": "your_token_here",
"Content-Type": "application/json"
}
Request Body:
{
"deviceId": "123456789012345678",
"startTime": "2024-02-10T00:00:00+08:00",
"endTime": "2024-02-10T23:59:59+08:00",
"keys": ["pvInputPower", "acOutputActivePower", ...]
}
Response:
{
"data": {
"pvInputPower": [
{"ts": 1234567890, "value": 2500},
{"ts": 1234567900, "value": 2600}
],
"acOutputActivePower": [...]
}
}
URL: https://solar.siseli.com/api/stateAttributeSummary/category/yearly
Method: POST
Request Body:
{
"stationId": "123456789012345678",
"year": 2024
}
Response:
{
"data": {
"summary": [
{
"month": 1,
"pvGenerated": 201.06,
"gridImport": 0,
"gridExport": 0
}
]
}
}
User Configuration
↓
Config Entry Created
↓
API Client Initialized
↓
Coordinator Created
↓
Initial Data Fetch
↓
Sensors Created
↓
┌─────────────────┐
│ Every 5 min │
│ Coordinator │
│ Updates Data │
└────────┬────────┘
↓
Sensors Update
↓
State Changes
↓
HA Event System
const.pySENSOR_DEFINITIONS = {
"newSensorKey": {
"name": "New Sensor Name",
"unit": "W", # or kWh, A, V, %
"device_class": "power", # or energy, current, voltage, battery
"icon": "mdi:icon-name",
},
}
In api.py, add the key to the request payload:
payload = {
"deviceId": self.device_id,
"startTime": start_time.strftime("%Y-%m-%dT%H:%M:%S+08:00"),
"endTime": end_time.strftime("%Y-%m-%dT%H:%M:%S+08:00"),
"keys": [
"pvInputPower",
"newSensorKey", # Add here
# ... other keys
],
}
If the sensor value needs calculation, add logic in fetch_latest_data():
if "someValue" in latest_values:
value = float(latest_values.get("someValue", 0))
latest_values["newSensorKey"] = value * 2 # Example calculation
Create a test config entry and verify the sensor appears.
battery_power = (discharge_current - charge_current) × voltage
Where:
grid_import = max(0, ac_output - pv_power + battery_power + feed_in)
This is a simplified calculation. In reality:
solar_percentage = (solar_used / total_consumption) × 100
Where:
# Install test dependencies
pip install pytest pytest-homeassistant-custom-component
# Run all tests
pytest tests/
# Run specific test
pytest tests/test_config_flow.py -v
# Run with coverage
pytest --cov=custom_components.solar_of_things --cov-report=html
Setup Test Instance:
# In Home Assistant development container
hass -c config --debug
Add Integration:
Verify Sensors:
sensor.solar_station_* entitiesTest Updates:
Fork the repository
Clone your fork:
git clone https://github.com/yourusername/solar-of-things-ha.git
cd solar-of-things-ha
Create development environment:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements_dev.txt
Install pre-commit hooks:
pre-commit install
black custom_components/solar_of_things/isort custom_components/solar_of_things/pylint custom_components/solar_of_things/mypy custom_components/solar_of_things/git checkout -b feature/my-featurepytestblack . && isort . && pylint custom_components/Follow conventional commits:
feat: New featurefix: Bug fixdocs: Documentation changestest: Test changesrefactor: Code refactoringchore: Maintenance tasksExample: feat: add support for inverter temperature sensor
Add to configuration.yaml:
logger:
default: info
logs:
custom_components.solar_of_things: debug
Debugging:
# In api.py, add logging
_LOGGER.debug("API request: %s", payload)
_LOGGER.debug("API response: %s", response.text)
Common causes:
Check:
Verify:
.gitignore for sensitive filesHistorical Data Import
Advanced Calculations
Additional Sensors
Automation Helpers
UI Improvements
Have an idea? Open an issue on GitHub to discuss!
This project is licensed under the MIT License - see the LICENSE file for details.