- MOCK_MODE=true bypasses API call with hardcoded critical readings - Aeration recommendation via Co2Level thresholds (resolveLevel / isAlertable) - Webhook URL now defaults to configured Teams channel
This commit is contained in:
@@ -27,7 +27,8 @@ public class NotificationProperties {
|
|||||||
private String apiUrl = "http://localhost:8080";
|
private String apiUrl = "http://localhost:8080";
|
||||||
private long pollIntervalMs = 60_000;
|
private long pollIntervalMs = 60_000;
|
||||||
private Thresholds thresholds = new Thresholds();
|
private Thresholds thresholds = new Thresholds();
|
||||||
private String alertFromLevel = "poor";
|
private String alertFromLevel = "poor";
|
||||||
|
private boolean mockMode = false;
|
||||||
|
|
||||||
public String getApiUrl() { return apiUrl; }
|
public String getApiUrl() { return apiUrl; }
|
||||||
public void setApiUrl(String apiUrl) { this.apiUrl = apiUrl; }
|
public void setApiUrl(String apiUrl) { this.apiUrl = apiUrl; }
|
||||||
@@ -40,6 +41,9 @@ public class NotificationProperties {
|
|||||||
|
|
||||||
public String getAlertFromLevel() { return alertFromLevel; }
|
public String getAlertFromLevel() { return alertFromLevel; }
|
||||||
public void setAlertFromLevel(String alertFromLevel) { this.alertFromLevel = alertFromLevel; }
|
public void setAlertFromLevel(String alertFromLevel) { this.alertFromLevel = alertFromLevel; }
|
||||||
|
|
||||||
|
public boolean isMockMode() { return mockMode; }
|
||||||
|
public void setMockMode(boolean mockMode) { this.mockMode = mockMode; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Thresholds {
|
public static class Thresholds {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -17,9 +18,15 @@ public class AirQualityScheduler {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AirQualityScheduler.class);
|
private static final Logger log = LoggerFactory.getLogger(AirQualityScheduler.class);
|
||||||
|
|
||||||
private final AirQualityService airQualityService;
|
private static final List<SensorReading> MOCK_READINGS = List.of(
|
||||||
private final TeamsNotificationService teamsService;
|
new SensorReading("A1", "Salle A1", 2150, 23.5, 55, "closed", Instant.now()),
|
||||||
private final NotificationProperties props;
|
new SensorReading("A2", "Salle A2", 1520, 22.0, 48, "open", Instant.now()),
|
||||||
|
new SensorReading("B1", "Salle B1", 780, 21.0, 42, "closed", Instant.now())
|
||||||
|
);
|
||||||
|
|
||||||
|
private final AirQualityService airQualityService;
|
||||||
|
private final TeamsNotificationService teamsService;
|
||||||
|
private final NotificationProperties props;
|
||||||
|
|
||||||
public AirQualityScheduler(AirQualityService airQualityService,
|
public AirQualityScheduler(AirQualityService airQualityService,
|
||||||
TeamsNotificationService teamsService,
|
TeamsNotificationService teamsService,
|
||||||
@@ -29,20 +36,16 @@ public class AirQualityScheduler {
|
|||||||
this.props = props;
|
this.props = props;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Scheduled(fixedDelayString = "${notification.air-quality.poll-interval-ms:60000}",
|
||||||
* Polls air quality data at the configured interval and sends a Teams alert
|
initialDelayString = "5000")
|
||||||
* for each room whose CO₂ level reaches or exceeds the configured threshold.
|
|
||||||
*
|
|
||||||
* The interval is read from the environment variable POLL_INTERVAL_MS
|
|
||||||
* (default: 60 000 ms). Spring's @Scheduled only supports fixed values at
|
|
||||||
* compile-time, so we use fixedDelayString with a SpEL expression instead.
|
|
||||||
*/
|
|
||||||
@Scheduled(fixedDelayString = "${notification.air-quality.poll-interval-ms:60000}",
|
|
||||||
initialDelayString = "5000")
|
|
||||||
public void checkAirQuality() {
|
public void checkAirQuality() {
|
||||||
log.debug("Polling air quality data…");
|
boolean mockMode = props.getAirQuality().isMockMode();
|
||||||
|
log.debug("Polling air quality data… (mock={})", mockMode);
|
||||||
|
|
||||||
|
List<SensorReading> readings = mockMode
|
||||||
|
? MOCK_READINGS
|
||||||
|
: airQualityService.fetchLatestReadings();
|
||||||
|
|
||||||
List<SensorReading> readings = airQualityService.fetchLatestReadings();
|
|
||||||
if (readings.isEmpty()) {
|
if (readings.isEmpty()) {
|
||||||
log.warn("No readings returned — skipping this cycle");
|
log.warn("No readings returned — skipping this cycle");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ spring:
|
|||||||
|
|
||||||
notification:
|
notification:
|
||||||
teams:
|
teams:
|
||||||
webhook-url: ${TEAMS_WEBHOOK_URL:}
|
webhook-url: ${TEAMS_WEBHOOK_URL:https://defaulta372f724c0b24ea0abfb0eb8c6f84e.40.environment.api.powerplatform.com:443/powerautomate/automations/direct/workflows/e661f41b50314eeebaccc123a0fcc129/triggers/manual/paths/invoke?api-version=1&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=0L78wU0kY2jjnXUwehf6lkDnA61vQOD4SuTHcRsdOX8}
|
||||||
air-quality:
|
air-quality:
|
||||||
api-url: ${AIR_QUALITY_API_URL:http://localhost:8080}
|
api-url: ${AIR_QUALITY_API_URL:http://localhost:8080}
|
||||||
poll-interval-ms: ${POLL_INTERVAL_MS:60000}
|
poll-interval-ms: ${POLL_INTERVAL_MS:60000}
|
||||||
@@ -15,3 +15,5 @@ notification:
|
|||||||
critical: 2000
|
critical: 2000
|
||||||
# Minimum level that triggers a notification (excellent / good / moderate / poor / critical)
|
# Minimum level that triggers a notification (excellent / good / moderate / poor / critical)
|
||||||
alert-from-level: poor
|
alert-from-level: poor
|
||||||
|
# Set to true to skip the API call and use hardcoded mock readings (for local testing)
|
||||||
|
mock-mode: ${MOCK_MODE:false}
|
||||||
|
|||||||
Reference in New Issue
Block a user