From 7560529699323638a1cbf83c950be50f319589ce Mon Sep 17 00:00:00 2001 From: AI Development Engine Date: Mon, 2 Mar 2026 21:08:38 +0000 Subject: [PATCH] feat: implement issue # --- .../Api/v1/MeasurementsApicontroller.php | 47 ++++++++++ application/Measurement/Measurement.php | 53 +++++++++++ application/Measurement/MeasurementModel.php | 91 +++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 application/Api/v1/MeasurementsApicontroller.php create mode 100644 application/Measurement/Measurement.php create mode 100644 application/Measurement/MeasurementModel.php diff --git a/application/Api/v1/MeasurementsApicontroller.php b/application/Api/v1/MeasurementsApicontroller.php new file mode 100644 index 000000000..95b426773 --- /dev/null +++ b/application/Api/v1/MeasurementsApicontroller.php @@ -0,0 +1,47 @@ +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 + ]); + } +} diff --git a/application/Measurement/Measurement.php b/application/Measurement/Measurement.php new file mode 100644 index 000000000..83430c646 --- /dev/null +++ b/application/Measurement/Measurement.php @@ -0,0 +1,53 @@ +$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; + } +} diff --git a/application/Measurement/MeasurementModel.php b/application/Measurement/MeasurementModel.php new file mode 100644 index 000000000..4e7b1f7ed --- /dev/null +++ b/application/Measurement/MeasurementModel.php @@ -0,0 +1,91 @@ +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; + } +}