mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-25 01:41:40 +00:00
Metrics and lighting implementation (#116)
Implements metrics and lighting control.
This commit is contained in:
@@ -47,7 +47,7 @@ public class HardwareManager {
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final NTDataChangeListener ledModeListener;
|
||||
|
||||
public final VisionLED visionLED;
|
||||
public final VisionLED visionLED; // May be null if no LED is specified
|
||||
|
||||
public static HardwareManager getInstance() {
|
||||
if (instance == null) {
|
||||
@@ -61,28 +61,47 @@ public class HardwareManager {
|
||||
CustomGPIO.setConfig(hardwareConfig);
|
||||
MetricsBase.setConfig(hardwareConfig);
|
||||
|
||||
statusLED = new StatusLED(hardwareConfig.statusRGBPins);
|
||||
statusLED =
|
||||
hardwareConfig.statusRGBPins.size() == 3
|
||||
? new StatusLED(hardwareConfig.statusRGBPins)
|
||||
: null;
|
||||
visionLED =
|
||||
new VisionLED(
|
||||
hardwareConfig.ledPins,
|
||||
hardwareConfig.ledPWMFrequency,
|
||||
(hardwareConfig.ledPWMRange != null && hardwareConfig.ledPWMRange.size() == 2)
|
||||
? hardwareConfig.ledPWMRange.get(1)
|
||||
: 0);
|
||||
hardwareConfig.ledPins.isEmpty()
|
||||
? null
|
||||
: new VisionLED(
|
||||
hardwareConfig.ledPins,
|
||||
hardwareConfig.ledPWMFrequency,
|
||||
(hardwareConfig.ledPWMRange != null && hardwareConfig.ledPWMRange.size() == 2)
|
||||
? hardwareConfig.ledPWMRange.get(1)
|
||||
: 0);
|
||||
|
||||
ledModeEntry = NetworkTablesManager.getInstance().kRootTable.getEntry("ledMode");
|
||||
ledModeEntry.setNumber(VisionLEDMode.VLM_DEFAULT.value);
|
||||
ledModeListener = new NTDataChangeListener(ledModeEntry, visionLED::onLedModeChange);
|
||||
ledModeListener =
|
||||
visionLED == null
|
||||
? null
|
||||
: new NTDataChangeListener(ledModeEntry, visionLED::onLedModeChange);
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::onJvmExit));
|
||||
|
||||
if (visionLED != null)
|
||||
visionLED.setBrightness(
|
||||
ConfigManager.getInstance().getConfig().getHardwareSettings().ledBrightnessPercentage);
|
||||
|
||||
// Start hardware metrics thread (Disabled until implemented)
|
||||
// if (Platform.isLinux()) MetricsPublisher.getInstance().startTask();
|
||||
}
|
||||
|
||||
public void setBrightnessPercent(int percent) {
|
||||
ConfigManager.getInstance().getConfig().getHardwareSettings().ledBrightnessPercentage = percent;
|
||||
if (visionLED != null) visionLED.setBrightness(percent);
|
||||
ConfigManager.getInstance().requestSave();
|
||||
logger.info("Setting led brightness to " + percent + "%");
|
||||
}
|
||||
|
||||
private void onJvmExit() {
|
||||
logger.info("Shutting down...");
|
||||
visionLED.setState(false);
|
||||
logger.info("Shutting down LEDs...");
|
||||
if (visionLED != null) visionLED.setState(false);
|
||||
}
|
||||
|
||||
public boolean restartDevice() {
|
||||
|
||||
@@ -19,17 +19,23 @@ package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class CPUMetrics extends MetricsBase {
|
||||
|
||||
public CPUMetrics() {}
|
||||
private String cpuMemSplit = null;
|
||||
|
||||
public String getMemory() {
|
||||
if (cpuMemoryCommand.isEmpty()) return "";
|
||||
return execute(cpuMemoryCommand);
|
||||
if (cpuMemSplit == null) {
|
||||
cpuMemSplit = execute(cpuMemoryCommand);
|
||||
}
|
||||
return cpuMemSplit;
|
||||
}
|
||||
|
||||
// TODO: Command should return in Celsius
|
||||
public String getTemp() {
|
||||
if (cpuTemperatureCommand.isEmpty()) return "";
|
||||
return execute(cpuTemperatureCommand);
|
||||
try {
|
||||
return execute(cpuTemperatureCommand);
|
||||
} catch (Exception e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public String getUtilization() {
|
||||
|
||||
@@ -18,11 +18,16 @@
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class GPUMetrics extends MetricsBase {
|
||||
public String getMemory() {
|
||||
return execute(gpuMemoryCommand);
|
||||
private String gpuMemSplit = null;
|
||||
|
||||
public String getGPUMemorySplit() {
|
||||
if (gpuMemSplit == null) {
|
||||
gpuMemSplit = execute(gpuMemoryCommand);
|
||||
}
|
||||
return gpuMemSplit;
|
||||
}
|
||||
|
||||
public String getTemp() {
|
||||
return execute(gpuTemperatureCommand);
|
||||
public String getMallocedMemory() {
|
||||
return execute(gpuMemUsageCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,18 +26,18 @@ import org.photonvision.common.util.ShellExec;
|
||||
public abstract class MetricsBase {
|
||||
private static final Logger logger = new Logger(MetricsBase.class, LogGroup.General);
|
||||
// CPU
|
||||
public static String cpuMemoryCommand = "sudo vcgencmd get_mem arm | grep -Eo '[0-9]+'";
|
||||
public static String cpuMemoryCommand = "vcgencmd get_mem arm | grep -Eo '[0-9]+'";
|
||||
public static String cpuTemperatureCommand =
|
||||
"sudo cat /sys/class/thermal/thermal_zone0/temp | grep -x -E '[0-9]+'";
|
||||
"sed 's/.\\{3\\}$/.&/' <<< cat /sys/class/thermal/thermal_zone0/temp";
|
||||
public static String cpuUtilizationCommand =
|
||||
"sudo top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}'";
|
||||
"top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}'";
|
||||
|
||||
// GPU
|
||||
public static String gpuMemoryCommand = "sudo vcgencmd get_mem gpu | grep -Eo '[0-9]+'";
|
||||
public static String gpuTemperatureCommand = "sudo vcgencmd measure_temp | sed 's/[^0-9]*//g'\n";
|
||||
public static String gpuMemoryCommand = "vcgencmd get_mem gpu | grep -Eo '[0-9]+'";
|
||||
public static String gpuMemUsageCommand = "vcgencmd get_mem malloc | grep -Eo '[0-9]+'";
|
||||
|
||||
// RAM
|
||||
public static String ramUsageCommand = "sudo free | awk -v i=2 -v j=3 'FNR == i {print $j}'";
|
||||
public static String ramUsageCommand = "free --mega | awk -v i=2 -v j=3 'FNR == i {print $j}'";
|
||||
|
||||
private static ShellExec runCommand = new ShellExec(true, true);
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class MetricsBase {
|
||||
cpuUtilizationCommand = config.cpuUtilCommand;
|
||||
|
||||
gpuMemoryCommand = config.gpuMemoryCommand;
|
||||
gpuTemperatureCommand = config.gpuTempCommand;
|
||||
gpuMemUsageCommand = config.gpuMemUsageCommand;
|
||||
|
||||
ramUsageCommand = config.ramUtilCommand;
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.HashMap;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
import org.photonvision.common.hardware.Platform;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
import org.photonvision.common.util.TimedTaskManager;
|
||||
import org.photonvision.server.SocketHandler;
|
||||
|
||||
public class MetricsPublisher {
|
||||
private final HashMap<String, String> metrics;
|
||||
private static final Logger logger = new Logger(MetricsPublisher.class, LogGroup.General);
|
||||
private static CPUMetrics cpuMetrics;
|
||||
private static GPUMetrics gpuMetrics;
|
||||
@@ -39,26 +39,6 @@ public class MetricsPublisher {
|
||||
cpuMetrics = new CPUMetrics();
|
||||
gpuMetrics = new GPUMetrics();
|
||||
ramMetrics = new RAMMetrics();
|
||||
|
||||
metrics = new HashMap<>();
|
||||
}
|
||||
|
||||
public void startTask() {
|
||||
TimedTaskManager.getInstance()
|
||||
.addTask(
|
||||
"Metrics",
|
||||
() -> {
|
||||
metrics.put("cpuTemp", cpuMetrics.getTemp());
|
||||
metrics.put("cpuUtil", cpuMetrics.getUtilization());
|
||||
metrics.put("cpuMem", cpuMetrics.getMemory());
|
||||
metrics.put("gpuTemp", gpuMetrics.getTemp());
|
||||
metrics.put("gpuMem", gpuMetrics.getMemory());
|
||||
metrics.put("ramUtil", ramMetrics.getUsedRam());
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(new OutgoingUIEvent<>("metrics", metrics));
|
||||
},
|
||||
1000);
|
||||
}
|
||||
|
||||
public void stopTask() {
|
||||
@@ -66,6 +46,32 @@ public class MetricsPublisher {
|
||||
logger.info("This device does not support running bash commands. Stopped metrics thread.");
|
||||
}
|
||||
|
||||
public void publish() {
|
||||
if (!Platform.isRaspberryPi()) {
|
||||
logger.debug("Ignoring metrics on non-Pi devices");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Publishing Metrics...");
|
||||
final var metrics = new HashMap<String, String>();
|
||||
|
||||
metrics.put("cpuTemp", cpuMetrics.getTemp());
|
||||
metrics.put("cpuUtil", cpuMetrics.getUtilization());
|
||||
metrics.put("cpuMem", cpuMetrics.getMemory());
|
||||
metrics.put("gpuMem", gpuMetrics.getGPUMemorySplit());
|
||||
metrics.put("ramUtil", ramMetrics.getUsedRam());
|
||||
metrics.put("gpuMemUtil", gpuMetrics.getMallocedMemory());
|
||||
|
||||
var retMap = new HashMap<String, Object>();
|
||||
retMap.put("metrics", metrics);
|
||||
|
||||
try {
|
||||
SocketHandler.getInstance().broadcastMessage(retMap, null);
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.error("Exception while sending metrics!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Singleton {
|
||||
public static final MetricsPublisher INSTANCE = new MetricsPublisher();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user