539 lines
8.0 KiB
Markdown
539 lines
8.0 KiB
Markdown
# LitoralRegas Backend
|
|
|
|
Spring Boot backend for the LitoralRegas agricultural monitoring and control platform.
|
|
|
|
This backend communicates with agricultural controllers through Modbus, builds dynamic acquisition plans based on installed modules, collects live telemetry, stores historical data, and exposes APIs consumed by the frontend dashboard.
|
|
|
|
---
|
|
|
|
# Features
|
|
|
|
* Modbus TCP communication
|
|
* Dynamic controller capability discovery
|
|
* Sensor definition import system
|
|
* Live telemetry acquisition
|
|
* Telemetry cache layer
|
|
* Historical telemetry storage
|
|
* Climate module API
|
|
* Meteorology module API
|
|
* Irrigation module foundation
|
|
* Historical chart aggregation endpoints
|
|
* SQLite persistence
|
|
|
|
---
|
|
|
|
# Technology Stack
|
|
|
|
* Java 21
|
|
* Spring Boot
|
|
* Spring Web
|
|
* Spring Data JPA
|
|
* SQLite
|
|
* Maven
|
|
* Modbus TCP
|
|
|
|
---
|
|
|
|
# Architecture Overview
|
|
|
|
```txt
|
|
Sensor Definitions
|
|
↓
|
|
Controller Capabilities
|
|
↓
|
|
Acquisition Plan Builder
|
|
↓
|
|
Telemetry Acquisition Scheduler
|
|
↓
|
|
Telemetry Cache
|
|
↓
|
|
Historian + Module APIs
|
|
↓
|
|
Frontend Dashboard
|
|
```
|
|
|
|
---
|
|
|
|
# Core Concepts
|
|
|
|
## Sensor Definitions
|
|
|
|
The `sensor_definition` table contains the full catalog of known sensors.
|
|
|
|
A controller installation may not use every sensor present in the catalog.
|
|
|
|
The acquisition plan decides which sensors are actually polled.
|
|
|
|
---
|
|
|
|
## Controller Capabilities
|
|
|
|
Controller capabilities are read directly from Modbus registers.
|
|
|
|
Current capability model:
|
|
|
|
```txt
|
|
Register 6 → irrigationControllerCount
|
|
Register 7 → fertilizerChannelCount
|
|
Register 8 → feature flags
|
|
Register 9 → climateGreenhouseCount
|
|
```
|
|
|
|
Feature flags:
|
|
|
|
```txt
|
|
bit 0 → climateEnabled
|
|
bit 1 → irrigationEnabled
|
|
bit 2 → lightingEnabled
|
|
```
|
|
|
|
---
|
|
|
|
## Acquisition Plan
|
|
|
|
The acquisition plan dynamically selects sensors based on:
|
|
|
|
* Installed controller modules
|
|
* Greenhouse count
|
|
* Irrigation controller count
|
|
* Sensor category
|
|
* Modbus address ranges
|
|
|
|
This prevents polling sensors that do not exist in a specific installation.
|
|
|
|
---
|
|
|
|
## Telemetry Cache
|
|
|
|
The telemetry cache stores the latest acquired value for each sensor.
|
|
|
|
Module APIs read from the cache instead of directly querying Modbus.
|
|
|
|
---
|
|
|
|
## Historian
|
|
|
|
The historian stores telemetry over time.
|
|
|
|
It supports:
|
|
|
|
* historical chart series
|
|
* accumulated values
|
|
* time range queries
|
|
* future workspace/chart persistence
|
|
|
|
---
|
|
|
|
# Project Structure
|
|
|
|
```txt
|
|
src/main/java/com/litoralregas/backend
|
|
├── acquisition
|
|
├── historian
|
|
├── modbus
|
|
├── modules
|
|
│ ├── climate
|
|
│ ├── irrigation
|
|
│ ├── meteo
|
|
│ └── shared
|
|
├── sensor
|
|
├── telemetry
|
|
└── config
|
|
```
|
|
|
|
---
|
|
|
|
# Running the Backend
|
|
|
|
## Requirements
|
|
|
|
* Java 21+
|
|
* Maven
|
|
* SQLite
|
|
* Reachable controller or Modbus simulator
|
|
|
|
---
|
|
|
|
## Start Backend
|
|
|
|
```bash
|
|
mvn spring-boot:run
|
|
```
|
|
|
|
Default backend URL:
|
|
|
|
```txt
|
|
http://localhost:18450
|
|
```
|
|
|
|
---
|
|
|
|
# Configuration
|
|
|
|
Main configuration file:
|
|
|
|
```txt
|
|
src/main/resources/application.yaml
|
|
```
|
|
|
|
Example acquisition scheduler configuration:
|
|
|
|
```yaml
|
|
litoralregas:
|
|
acquisition:
|
|
scheduler:
|
|
enabled: true
|
|
fixed-delay-millis: 10000
|
|
```
|
|
|
|
Important:
|
|
|
|
YAML comments must be on a separate line.
|
|
|
|
Correct:
|
|
|
|
```yaml
|
|
fixed-delay-millis: 10000
|
|
# Longer delay between acquisition cycles
|
|
```
|
|
|
|
Wrong:
|
|
|
|
```yaml
|
|
fixed-delay-millis: 10000 // comment
|
|
```
|
|
|
|
---
|
|
|
|
# Database
|
|
|
|
Current database engine:
|
|
|
|
```txt
|
|
SQLite
|
|
```
|
|
|
|
Main table:
|
|
|
|
```sql
|
|
CREATE TABLE sensor_definition (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name VARCHAR(255) NOT NULL,
|
|
modbus_address INTEGER NOT NULL,
|
|
bit_offset INTEGER,
|
|
value_type VARCHAR(50) NOT NULL,
|
|
unit VARCHAR(50),
|
|
decimal_places INTEGER NOT NULL DEFAULT 0,
|
|
category VARCHAR(100) NOT NULL,
|
|
source_type VARCHAR(50) NOT NULL,
|
|
polling_interval_seconds INTEGER NOT NULL DEFAULT 1,
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
# Sensor Definition Import
|
|
|
|
Sensor definitions are imported from:
|
|
|
|
```txt
|
|
src/main/resources/config/sensor-map.txt
|
|
```
|
|
|
|
Run import manually:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:18450/api/sensor-definition-import/run
|
|
```
|
|
|
|
The importer:
|
|
|
|
* imports missing sensors
|
|
* updates safe metadata
|
|
* skips duplicates safely
|
|
* supports clean reimports during development
|
|
|
|
---
|
|
|
|
# Clean Development Reimport
|
|
|
|
To completely reset sensor definitions during development:
|
|
|
|
```sql
|
|
DELETE FROM sensor_definition;
|
|
|
|
DELETE FROM sqlite_sequence
|
|
WHERE name = 'sensor_definition';
|
|
```
|
|
|
|
Then re-run:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:18450/api/sensor-definition-import/run
|
|
```
|
|
|
|
---
|
|
|
|
# Main API Endpoints
|
|
|
|
## Acquisition Plan
|
|
|
|
```http
|
|
GET /api/acquisition/plan
|
|
```
|
|
|
|
Returns:
|
|
|
|
* module availability
|
|
* greenhouse count
|
|
* irrigation controller count
|
|
* selected sensor IDs
|
|
|
|
---
|
|
|
|
## Latest Telemetry
|
|
|
|
```http
|
|
GET /api/telemetry/latest
|
|
```
|
|
|
|
Returns latest cached telemetry values.
|
|
|
|
---
|
|
|
|
## Meteo Module
|
|
|
|
```http
|
|
GET /api/modules/meteo
|
|
```
|
|
|
|
Provides:
|
|
|
|
* exterior temperature
|
|
* exterior humidity
|
|
* wind speed
|
|
* wind direction
|
|
* radiation
|
|
* rain sensors
|
|
* CO2 overview
|
|
|
|
---
|
|
|
|
## Climate Module
|
|
|
|
```http
|
|
GET /api/modules/climate
|
|
```
|
|
|
|
Provides:
|
|
|
|
* greenhouse temperature
|
|
* greenhouse humidity
|
|
* CO2
|
|
* ventilation
|
|
* extractors
|
|
* screens
|
|
* windows
|
|
* lighting sectors
|
|
* soil humidity
|
|
* soil temperature
|
|
|
|
---
|
|
|
|
## Historical Accumulation
|
|
|
|
```http
|
|
GET /api/historian/accumulated
|
|
```
|
|
|
|
Example:
|
|
|
|
```http
|
|
GET /api/historian/accumulated?key=meteo.chuva.1&range=30d
|
|
```
|
|
|
|
Supported ranges:
|
|
|
|
```txt
|
|
7d
|
|
30d
|
|
month
|
|
year
|
|
```
|
|
|
|
---
|
|
|
|
# Dynamic Module Strategy
|
|
|
|
Module availability is determined dynamically through:
|
|
|
|
```txt
|
|
ControllerCapabilities
|
|
↓
|
|
AcquisitionPlan
|
|
↓
|
|
TelemetryCache
|
|
```
|
|
|
|
This means:
|
|
|
|
* climate sensors are only acquired if climate exists
|
|
* irrigation sensors are only acquired if irrigation exists
|
|
* lighting sensors are only acquired if lighting exists
|
|
|
|
The frontend should eventually use acquisition plan data to decide which sections to render.
|
|
|
|
---
|
|
|
|
# Derived Sensors
|
|
|
|
Some sensors are virtual/computed values.
|
|
|
|
Examples:
|
|
|
|
```txt
|
|
DPV Estufa 1 → -121
|
|
Hum. Absoluta 1 → -141
|
|
```
|
|
|
|
These are NOT real Modbus registers.
|
|
|
|
Correct pipeline:
|
|
|
|
```txt
|
|
Raw temperature + humidity
|
|
↓
|
|
DerivedClimateService
|
|
↓
|
|
DPV / Absolute Humidity
|
|
↓
|
|
TelemetryCache + Historian
|
|
```
|
|
|
|
Negative Modbus addresses should never be polled directly.
|
|
|
|
---
|
|
|
|
# Current Development Notes
|
|
|
|
Disconnected sensors may return unrealistic values.
|
|
|
|
Examples:
|
|
|
|
* invalid temperature values
|
|
* unrealistic humidity values
|
|
* disconnected soil probes
|
|
|
|
This is expected in partially installed environments.
|
|
|
|
The backend currently exposes all acquired sensors.
|
|
|
|
The frontend chart builder will later allow users to choose only relevant variables.
|
|
|
|
---
|
|
|
|
# Planned Improvements
|
|
|
|
## Chart Variables API
|
|
|
|
Planned endpoint:
|
|
|
|
```http
|
|
GET /api/charts/variables?module=climate
|
|
```
|
|
|
|
Expected response:
|
|
|
|
```json
|
|
{
|
|
"sensorId": 13,
|
|
"name": "Temperatura estufa 1",
|
|
"key": "temperatura.estufa.1",
|
|
"historianKey": "climate.temperatura.estufa.1",
|
|
"module": "climate",
|
|
"unit": "C",
|
|
"category": "CLIMATE"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Derived Climate Values
|
|
|
|
Future derived telemetry:
|
|
|
|
* DPV
|
|
* absolute humidity
|
|
* dew point
|
|
* climate alarms
|
|
* sensor health
|
|
|
|
---
|
|
|
|
## Workspace System
|
|
|
|
Planned chart workspace support:
|
|
|
|
* save layouts
|
|
* detachable charts
|
|
* multi-monitor support
|
|
* reusable chart presets
|
|
* draggable variables
|
|
|
|
---
|
|
|
|
# Useful Development Commands
|
|
|
|
## Import Sensors
|
|
|
|
```bash
|
|
curl -X POST http://localhost:18450/api/sensor-definition-import/run
|
|
```
|
|
|
|
## Check Acquisition Plan
|
|
|
|
```bash
|
|
curl http://localhost:18450/api/acquisition/plan
|
|
```
|
|
|
|
## Check Meteo Module
|
|
|
|
```bash
|
|
curl http://localhost:18450/api/modules/meteo
|
|
```
|
|
|
|
## Check Climate Module
|
|
|
|
```bash
|
|
curl http://localhost:18450/api/modules/climate
|
|
```
|
|
|
|
## Check Latest Telemetry
|
|
|
|
```bash
|
|
curl http://localhost:18450/api/telemetry/latest
|
|
```
|
|
|
|
---
|
|
|
|
# Current Status
|
|
|
|
The backend foundation is currently stable for:
|
|
|
|
* sensor catalog import
|
|
* Modbus acquisition
|
|
* capability-based acquisition planning
|
|
* telemetry cache
|
|
* meteorology module
|
|
* climate module
|
|
* historical accumulation
|
|
* frontend integration
|
|
|
|
Next major milestone:
|
|
|
|
```txt
|
|
Chart Variables API + Derived Climate Telemetry
|
|
```
|