Refactor telemetry acquisition and add dynamic climate module support
This commit is contained in:
@@ -0,0 +1,538 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user