Add superuser endpoints for forced MACHINE relay control
- Implement emergency operations to forcibly enable or disable MACHINE relays (`forceTurnOnMachineRelay`). - Add OpenAPI specifications for `/modules/self-serve/lane/force/machine/enable` and `/modules/self-serve/lane/force/machine/disable`. - Update route definitions and introduce validation for input parameters.
This commit is contained in:
@@ -68,6 +68,47 @@ trait selfserve_lane_relay_controller_t
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force turn on the MACHINE relay, bypassing allowed services gating.
|
||||
* Intended for superuser/emergency operations.
|
||||
* @param int|null $duration Optional auto-off duration in seconds
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function forceTurnOnMachineRelay(?int $duration = null): bool
|
||||
{
|
||||
// Require department lane object
|
||||
if (empty($this->department_lane)) throw new \Exception("Department lane object not found for lane ID {$this->id}");
|
||||
// Basic sanity checks on lane status (still disallow clearly invalid states)
|
||||
if ($this->getLaneStatus()->equals(selfserve_lane_status::CLOSED)) throw new \Exception("Cannot turn on relay on CLOSED lane");
|
||||
if ($this->getLaneStatus()->equals(selfserve_lane_status::MAINTENANCE)) throw new \Exception("Cannot turn on relay on MAINTENANCE lane");
|
||||
if ($this->getLaneStatus()->equals(selfserve_lane_status::FAULT)) throw new \Exception("Cannot turn on relay on FAULT lane");
|
||||
// Directly control Shelly without checking allowed services
|
||||
$relay_id = $this->department_lane->relay_machine_id->value();
|
||||
if (empty($relay_id)) {
|
||||
throw new \Exception("Invalid relay ID for MACHINE relay");
|
||||
}
|
||||
$shelly = new shelly();
|
||||
$shelly->requireModuleEnabled();
|
||||
$shelly->requireValidSecretKey();
|
||||
$parameters = new shelly_request_body_get_states();
|
||||
$parameters->ids = [$relay_id];
|
||||
$parameters->select = ['status'];
|
||||
$result = $shelly->sendPostRequest('/v2/devices/api/get', (array)$parameters);
|
||||
// Wait 1 second
|
||||
sleep(1);
|
||||
// Format the result
|
||||
$result = array_map(function ($device) {
|
||||
return (new shelly_device_switch())->populate($device);
|
||||
}, $result);
|
||||
// Turn on the switch
|
||||
foreach ($result as $device) {
|
||||
if ($duration !== null) $device->toggle_after = $duration;
|
||||
$device->switch(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off the lane relay
|
||||
* @param selfserve_lane_relay $relay The relay to turn off (MACHINE)
|
||||
|
||||
@@ -207,5 +207,97 @@ class moduleSelfServeRoute
|
||||
}, [
|
||||
'modules_selfserve_lane_relay_enable_machine' => 'Manually enable MACHINE relay for a lane (requires allowed task to be present)'
|
||||
]);
|
||||
|
||||
/** Modules > Self Serve > Lane > Force > MACHINE enable (simulate started wash) */
|
||||
$this->post('/modules/self-serve/lane/force/machine/enable', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_force_machine_enable');
|
||||
$selfserve = new selfserve();
|
||||
// Validate parameters
|
||||
self::requireParameters(['lane_id']);
|
||||
$lane_id = (int)$this->getParameter('lane_id');
|
||||
self::requireType($lane_id, self::type_int());
|
||||
self::requireMinValue($lane_id, 1);
|
||||
$duration = null;
|
||||
if ($this->isParametersSet(['duration'])) {
|
||||
$duration = (int)$this->getParameter('duration');
|
||||
self::requireMinValue($duration, 1);
|
||||
}
|
||||
$license_plate = $this->isParametersSet(['license_plate']) ? (string)$this->getParameter('license_plate') : null;
|
||||
$lane = $selfserve->lane($lane_id);
|
||||
try {
|
||||
// If lane looks idle/available, mark as occupied and in wash, set timers
|
||||
if ($lane->getLaneStatus()->equals(\modules\selfserve\helpers\selfserve_lane_status::AVAILABLE)) {
|
||||
$lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::OCCUPIED);
|
||||
}
|
||||
if (!$lane->getLaneState()->equals(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH)) {
|
||||
$lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH);
|
||||
}
|
||||
if ($license_plate !== null && $license_plate !== '') {
|
||||
$lane->setLicensePlate($license_plate);
|
||||
}
|
||||
if ((int)$lane->getWashStartTime() <= 0) {
|
||||
$lane->setWashStartTime(time());
|
||||
}
|
||||
// Force enable the machine relay (bypass gating)
|
||||
$lane->forceTurnOnMachineRelay($duration);
|
||||
$response->success([
|
||||
'lane_id' => $lane_id,
|
||||
'forced' => true,
|
||||
'machine' => 'ENABLED',
|
||||
'duration' => $duration,
|
||||
'status' => $lane->getLaneStatus()->name,
|
||||
'state' => $lane->getLaneState()->name,
|
||||
'wash_start_time' => $lane->getWashStartTime(),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$response->error('Failed to force-enable MACHINE: ' . $e->getMessage(), 400);
|
||||
}
|
||||
}, [
|
||||
'modules_selfserve_lane_force_machine_enable' => 'Force enable MACHINE relay and mark lane as in-wash (superusers only)'
|
||||
]);
|
||||
|
||||
/** Modules > Self Serve > Lane > Force > MACHINE disable (simulate started wash without machine) */
|
||||
$this->post('/modules/self-serve/lane/force/machine/disable', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_force_machine_disable');
|
||||
$selfserve = new selfserve();
|
||||
// Validate parameters
|
||||
self::requireParameters(['lane_id']);
|
||||
$lane_id = (int)$this->getParameter('lane_id');
|
||||
self::requireType($lane_id, self::type_int());
|
||||
self::requireMinValue($lane_id, 1);
|
||||
$license_plate = $this->isParametersSet(['license_plate']) ? (string)$this->getParameter('license_plate') : null;
|
||||
$lane = $selfserve->lane($lane_id);
|
||||
try {
|
||||
// Ensure lane reflects an ongoing wash, but with machine off
|
||||
if ($lane->getLaneStatus()->equals(\modules\selfserve\helpers\selfserve_lane_status::AVAILABLE)) {
|
||||
$lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::OCCUPIED);
|
||||
}
|
||||
if (!$lane->getLaneState()->equals(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH)) {
|
||||
$lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH);
|
||||
}
|
||||
if ($license_plate !== null && $license_plate !== '') {
|
||||
$lane->setLicensePlate($license_plate);
|
||||
}
|
||||
if ((int)$lane->getWashStartTime() <= 0) {
|
||||
$lane->setWashStartTime(time());
|
||||
}
|
||||
// Turn off the machine relay if currently on
|
||||
try { $lane->turnOffRelay(\modules\selfserve\helpers\selfserve_lane_relay::MACHINE); } catch (\Throwable $ignored) {}
|
||||
$response->success([
|
||||
'lane_id' => $lane_id,
|
||||
'forced' => true,
|
||||
'machine' => 'DISABLED',
|
||||
'status' => $lane->getLaneStatus()->name,
|
||||
'state' => $lane->getLaneState()->name,
|
||||
'wash_start_time' => $lane->getWashStartTime(),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$response->error('Failed to force-disable MACHINE: ' . $e->getMessage(), 400);
|
||||
}
|
||||
}, [
|
||||
'modules_selfserve_lane_force_machine_disable' => 'Force disable MACHINE relay but keep lane as in-wash (superusers only)'
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user