1 Commits

Author SHA1 Message Date
AI Development Engine
7560529699 feat: implement issue # 2026-03-02 21:08:38 +00:00
3 changed files with 191 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<?php
require_once(APPDIR."/Measurement/Measurement.php");
require_once(APPDIR."/Measurement/MeasurementModel.php");
class MeasurementsApicontroller extends mfBaseApicontroller
{
protected function init()
{
// Initialize database connection if needed
$this->addRoute("/measurements/latest", "getLatestMeasurements", "GET");
}
/**
* Get the latest measurements grouped by unique device_id and sensor_id combinations
* Returns one measurement per combination, limited to 50 results
*/
protected function getLatestMeasurements()
{
// Get limit from query parameters, default to 50, max 100
$limit = 50;
if (isset($this->get['limit']) && is_numeric($this->get['limit'])) {
$limit = min(100, max(1, intval($this->get['limit'])));
}
// Get the latest measurements grouped by device_id and sensor_id
$measurements = MeasurementModel::getLatestGroupedByDeviceAndSensor($limit);
$result = [];
foreach ($measurements as $measurement) {
$result[] = [
'id' => $measurement->id,
'device_id' => $measurement->device_id,
'sensor_id' => $measurement->sensor_id,
'value' => (float)$measurement->value,
'unit' => $measurement->unit,
'timestamp' => $measurement->create,
'created_at' => date('Y-m-d H:i:s', $measurement->create)
];
}
return mfResponse::Ok([
'count' => count($result),
'measurements' => $result
]);
}
}

View File

@@ -0,0 +1,53 @@
<?php
class Measurement extends mfBaseModel
{
private $device;
private $sensor;
public function getProperty($name)
{
if ($this->$name == null) {
if (!$this->id) {
return null;
}
if($name == "device") {
$this->device = mfValuecache::singleton()->get("Device-id-".$this->device_id);
if($this->device === null) {
$this->device = new Device($this->device_id);
if($this->device->id) {
mfValuecache::singleton()->set("Device-id-".$this->device_id, $this->device);
}
}
return $this->device;
}
if($name == "sensor") {
// Sensor would be a separate entity if it exists
// For now, just return the sensor_id
return $this->sensor_id;
}
$classname = ucfirst($name);
$idfield = $name."_id";
if(property_exists($this->data, $idfield)) {
$this->$name = mfValuecache::singleton()->get("mfObjectmodel-$name-".$this->$idfield);
if(!$this->$name) {
$this->$name = new $classname($this->$idfield);
}
if($this->$name->id) {
mfValuecache::singleton()->set("mfObjectmodel-$name-".$this->$name->id, $this->$name);
return $this->$name;
} else {
return null;
}
}
return null;
}
return $this->$name;
}
}

View File

@@ -0,0 +1,91 @@
<?php
class MeasurementModel extends mfBaseModel
{
public static function search($filter = [])
{
$db = FronkDB::singleton();
$where = [];
$params = [];
if (isset($filter['device_id'])) {
if (is_array($filter['device_id'])) {
$where[] = "device_id IN (" . implode(',', array_map('intval', $filter['device_id'])) . ")";
} else {
$where[] = "device_id = " . intval($filter['device_id']);
}
}
if (isset($filter['sensor_id'])) {
if (is_array($filter['sensor_id'])) {
$where[] = "sensor_id IN (" . implode(',', array_map('intval', $filter['sensor_id'])) . ")";
} else {
$where[] = "sensor_id = " . intval($filter['sensor_id']);
}
}
$whereClause = '';
if (count($where)) {
$whereClause = ' WHERE ' . implode(' AND ', $where);
}
$order = ' ORDER BY `create` DESC';
if (isset($filter['order'])) {
$order = ' ORDER BY ' . $db->escape($filter['order']);
}
$limit = '';
if (isset($filter['limit'])) {
$limit = ' LIMIT ' . intval($filter['limit']);
}
$sql = "SELECT * FROM Measurement" . $whereClause . $order . $limit;
$res = $db->query($sql);
$measurements = [];
while ($row = $db->fetch_object($res)) {
$measurement = new Measurement();
$measurement->load($row);
$measurements[] = $measurement;
}
return $measurements;
}
public static function getLatestGroupedByDeviceAndSensor($limit = 50)
{
$db = FronkDB::singleton();
// Get the most recent measurements, grouped by unique device_id and sensor_id combinations
// This query gets the latest measurement for each device_id/sensor_id combination
$sql = "
SELECT m.*
FROM Measurement m
INNER JOIN (
SELECT device_id, sensor_id, MAX(`create`) as max_create
FROM (
SELECT device_id, sensor_id, `create`
FROM Measurement
ORDER BY `create` DESC
LIMIT 1000
) AS recent
GROUP BY device_id, sensor_id
) AS latest
ON m.device_id = latest.device_id
AND m.sensor_id = latest.sensor_id
AND m.`create` = latest.max_create
ORDER BY m.`create` DESC
LIMIT " . intval($limit);
$res = $db->query($sql);
$measurements = [];
while ($row = $db->fetch_object($res)) {
$measurement = new Measurement();
$measurement->load($row);
$measurements[] = $measurement;
}
return $measurements;
}
}