Predictions, ROI, Weather & Settings
ML prediction management, ROI calculations, weather data, and user preference endpoints.
Predictions
Base Route: /api/predictions
Authorization: Required
Train Model
Initiates ML model training for a Sun Source. This is an asynchronous operation — poll the status endpoint to track progress.
POST /api/predictions/train
Request Body
{
"sunSourceId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
Response 200 OK
{
"jobId": "train_7c9e6679_1718900520",
"status": "pending",
"predictions": null,
"metrics": null,
"error": null
}
Run Prediction
Generates energy predictions for the next 8 days using the trained model.
POST /api/predictions/predict
Request Body
{
"sunSourceId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
Response 200 OK
{
"jobId": "predict_7c9e6679_1718900520",
"status": "pending",
"predictions": null,
"metrics": null,
"error": null
}
Get Job Status
Polls the status of a training or prediction job.
GET /api/predictions/status/{jobId}
Response 200 OK
{
"jobId": "train_7c9e6679_1718900520",
"status": "completed",
"progress": 100,
"message": "Training completed successfully.",
"error": null,
"type": "train",
"sunSourceId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"updatedAt": "2025-06-20T14:30:00Z",
"metrics": {
"mae": 1.23,
"rmse": 2.45,
"r2": 0.92
},
"predictions": null,
"dataPointsUsed": 4320,
"modelMetrics": { ... }
}
Job Status Values
| Status | Description |
|---|---|
pending | Job queued, not yet started |
running | Job actively processing |
completed | Job finished successfully |
failed | Job failed (see error field) |
Get Latest Prediction
Returns the most recent prediction result for a Sun Source.
GET /api/predictions/latest/{sunSourceId}
Response 200 OK
{
"exists": true,
"data": {
"predictions": [
{
"date": "2025-06-21",
"solarProductionKwh": 22.5,
"loadConsumptionKwh": 14.2,
"batteryChargeKwh": 8.3
}
]
}
}
Get Model Info
Returns metadata about the trained model for a Sun Source.
GET /api/predictions/model-info/{sunSourceId}
Response 200 OK
{
"exists": true,
"data": {
"trainedAt": "2025-06-20T14:30:00Z",
"dataPointsUsed": 4320,
"metrics": {
"mae": 1.23,
"rmse": 2.45,
"r2": 0.92
}
}
}
ROI & Pricing
Base Route: /api/roi
Authorization: Required
List Price History
Returns all KWh price entries for a Sun Source, ordered by effective date.
GET /api/roi/{sunSourceId}/prices
Response 200 OK
[
{
"id": "a1b2c3d4-e5f6-...",
"sunSourceId": "7c9e6679-...",
"pricePerKwh": 0.25,
"effectiveFrom": "2024-01-01T00:00:00Z",
"createdAt": "2024-01-01T10:00:00Z"
},
{
"id": "b2c3d4e5-f6a7-...",
"sunSourceId": "7c9e6679-...",
"pricePerKwh": 0.28,
"effectiveFrom": "2025-01-01T00:00:00Z",
"createdAt": "2025-01-01T10:00:00Z"
}
]
Add Price Entry
POST /api/roi/{sunSourceId}/prices
Request Body
{
"pricePerKwh": 0.28,
"effectiveFrom": "2025-01-01T00:00:00Z"
}
Response 200 OK
Returns the created KwhPriceHistoryDto.
Update Price Entry
PUT /api/roi/prices/{priceId}
Request Body
{
"pricePerKwh": 0.30,
"effectiveFrom": "2025-01-01T00:00:00Z"
}
Delete Price Entry
DELETE /api/roi/prices/{priceId}
Returns 204 No Content.
Calculate ROI
Computes the full return-on-investment summary including daily breakdown, payback period, and monthly averages.
GET /api/roi/{sunSourceId}/calculate
Response 200 OK
{
"totalEnergyProducedKwh": 4250.00,
"totalSavings": 1062.50,
"currency": "EUR",
"firstDataDate": "2024-06-01T00:00:00Z",
"lastDataDate": "2025-06-20T00:00:00Z",
"dailyBreakdown": [
{
"date": "2025-06-20T00:00:00Z",
"energyProducedKwh": 21.50,
"pricePerKwh": 0.28,
"savings": 6.02,
"cumulativeSavings": 1062.50,
"isPrediction": false
}
],
"systemCost": 12500.00,
"roiPercentage": 8.50,
"paybackPeriodYears": 11.76,
"monthlyAvgSavings": 88.54,
"hasInvestmentData": true
}
Weather
Base Route: /api/weather
Authorization: Required
Get Weather Data
Returns weather forecast data for the next 8 days.
GET /api/weather/{sunSourceId}
Response 200 OK
[
{
"id": "...",
"sunSourceId": "7c9e6679-...",
"date": "2025-06-20T00:00:00Z",
"temperatureMax": 32.5,
"temperatureMin": 18.0,
"shortwaveRadiationSum": 25.8,
"weatherCode": 1,
"uvIndexMax": 9.2,
"precipitationSum": 0.0,
"sunrise": "2025-06-20T05:30:00",
"sunset": "2025-06-20T21:15:00"
}
]
Refresh Weather Data
Manually triggers a weather data refresh from Open-Meteo.
POST /api/weather/{sunSourceId}/refresh
Returns 200 OK on success, 503 Service Unavailable if Open-Meteo is unreachable.
Settings
Base Route: /api/settings
Authorization: Required
Setting Types
| Type ID | Name | Values | Description |
|---|---|---|---|
0 | DarkMode | "0" / "1" | UI dark mode preference |
1 | AutoRunPredictions | "0" / "1" | Enable auto-predictions (DailyPredictionJob) |
2 | AutoUpdateWeatherData | "0" / "1" | Enable auto weather refresh (UpdateWeatherDataJob) |
Get Setting
GET /api/settings/{settingType}
Response 200 OK
{
"value": "1"
}
Set Setting
POST /api/settings/{settingType}
Request Body
{
"value": "1"
}
Response 200 OK
{
"value": "1"
}
Sharing
Base Route: /api/sharing
Get Sharing Configuration
Authorization: Required
GET /api/sharing/{sunSourceId}
Response 200 OK
{
"sunSourceId": "7c9e6679-...",
"isEnabled": true,
"shareMonitor": true,
"shareWeather": true,
"shareForecast": false,
"shareReturns": false
}
Update Sharing Configuration
Authorization: Required
PUT /api/sharing/{sunSourceId}
Request Body
{
"isEnabled": true,
"shareMonitor": true,
"shareWeather": true,
"shareForecast": true,
"shareReturns": false
}
Public Endpoints (No Authentication)
These endpoints are accessible without authentication when sharing is enabled for the Sun Source.
| Endpoint | Sharing Flag | Description |
|---|---|---|
GET /api/sharing/public/{sunSourceId} | isEnabled | Basic source info |
GET /api/sharing/public/{sunSourceId}/metrics | shareMonitor | Latest metrics |
GET /api/sharing/public/{sunSourceId}/metrics/history | shareMonitor | Historical metrics |
GET /api/sharing/public/{sunSourceId}/weather | shareWeather | Weather data |
GET /api/sharing/public/{sunSourceId}/forecast | shareForecast | ML predictions |
GET /api/sharing/public/{sunSourceId}/roi | shareReturns | ROI summary |
Public Metrics History Parameters
| Parameter | Type | Default | Constraints |
|---|---|---|---|
startTime | DateTime | 24h ago | Optional |
endTime | DateTime | Now | Optional |
limit | int | 100 | 1–1,000 |
Export
Base Route: /api/export
Authorization: Required
Export as CSV
GET /api/export/{sunSourceId}/csv?startDate=2025-06-01&endDate=2025-06-20
Export as Excel
GET /api/export/{sunSourceId}/excel?startDate=2025-06-01&endDate=2025-06-20
Parameters (Both Endpoints)
| Parameter | Type | Required | Constraints |
|---|---|---|---|
startDate | DateTime | Yes | Start of export range |
endDate | DateTime | Yes | End of export range |
Maximum range: 33 days. Exceeding this returns 400 Bad Request.
Response
Returns the file download with appropriate Content-Type and Content-Disposition headers:
- CSV:
text/csv—export_{name}_{date}.csv - Excel:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet—export_{name}_{date}.xlsx
Upload
Base Route: /api/upload
Authorization: Required
Upload Image
POST /api/upload/image
Content-Type: multipart/form-data
Form Fields
| Field | Type | Description |
|---|---|---|
file | IFormFile | Image file |
Validation
| Rule | Constraint |
|---|---|
| Max file size | 5 MB |
| Allowed MIME types | image/jpeg, image/png, image/gif, image/webp |
| Magic byte validation | JPEG (FF D8 FF), PNG (89 50 4E 47), GIF (47 49 46 38), WebP (52 49 46 46) |
Response 200 OK
{
"url": "https://minio.ampra.solar/ampra-uploads/users/{userId}/{filename}"
}
Delete Image
DELETE /api/upload/image?url=https://minio.ampra.solar/ampra-uploads/users/{userId}/image.png
Validation
- URL must be absolute HTTP/HTTPS
- File must belong to the authenticated user (path must contain their user ID)
Response 200 OK
{
"message": "Image deleted."
}
Webhooks
Base Route: /api/webhook
Authorization: None (validated by webhook secret)
Receive Telemetry Data
POST /api/webhook/sunsource/{sunSourceId}
Content-Type: application/json
Payload
Raw JSON body containing telemetry data with the webhook secret. Maximum payload size: 64 KB.
The webhook secret is validated from the payload body. The data is then normalized using the same field alias system as MQTT ingestion and stored in MongoDB.
Response
| Status | Condition |
|---|---|
200 OK | Data accepted and stored |
400 Bad Request | Invalid payload or missing secret |
404 Not Found | Sun Source not found or inactive |
MQTT Auth (Internal)
Base Route: /api/internal/mqtt
Authorization: Internal API key (X-Internal-API-Key header)
These endpoints are called by the EMQX broker for client authentication and ACL checks. They are not intended for direct consumption.
Authenticate MQTT Client
POST /api/internal/mqtt/auth
X-Internal-API-Key: {internal-api-key}
Request Body
{
"clientId": "sunsource_7c9e6679",
"username": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"password": "ak_xxxxxxxxxxxxxxxxxxxxxxxx"
}
Response
{ "result": "allow", "is_superuser": false }
or
{ "result": "deny" }
Check MQTT ACL
POST /api/internal/mqtt/acl
X-Internal-API-Key: {internal-api-key}
Request Body
{
"clientId": "sunsource_7c9e6679",
"username": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"topic": "sunsource/7c9e6679-7425-40de-944b-e07fc1f90ae7/data",
"action": "publish"
}
Response
{ "result": "allow" }
Validates that the client is only allowed to publish to their own sunsource/{id}/data topic.