This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "{044221CE-A8E5-4413-A081-C3235FF73350}",
|
||||
"name": "TimerLifecycleProbe",
|
||||
"type": 3,
|
||||
"vendor": "ENELIX Test",
|
||||
"aliases": [],
|
||||
"parentRequirements": [],
|
||||
"childRequirements": [],
|
||||
"implemented": [],
|
||||
"prefix": "ENLTMR"
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Development-only native timer fixture. No device, manager or variable actions.
|
||||
class TimerLifecycleProbe extends IPSModule
|
||||
{
|
||||
public function Create(): void
|
||||
{
|
||||
parent::Create();
|
||||
$this->RegisterPropertyInteger('ReadWorkMs', 1500);
|
||||
$this->RegisterPropertyInteger('ReportWorkMs', 1500);
|
||||
$this->RegisterPropertyString('LifecycleMode', 'baseline');
|
||||
$this->RegisterAttributeInteger('ReadRuns', 0);
|
||||
$this->RegisterAttributeInteger('ReportRuns', 0);
|
||||
$this->RegisterAttributeInteger('CallbackEnds', 0);
|
||||
$this->RegisterAttributeInteger('ScriptEnds', 0);
|
||||
$this->RegisterTimer('Meldezyklus', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Report', 0); ENLTMR_MarkScriptEnd(\$_IPS['TARGET']);");
|
||||
$this->RegisterTimer('Rueckmeldesampler', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Read', 0); ENLTMR_MarkScriptEnd(\$_IPS['TARGET']);");
|
||||
}
|
||||
|
||||
public function ApplyChanges(): void
|
||||
{
|
||||
parent::ApplyChanges();
|
||||
$lock = 'ENELIX.TimerProbe.Battery.' . $this->InstanceID;
|
||||
if (!IPS_SemaphoreEnter($lock, 1000)) throw new RuntimeException('Probe battery busy');
|
||||
IPS_SemaphoreLeave($lock);
|
||||
$this->SetTimerInterval('Meldezyklus', 5000);
|
||||
$this->SetTimerInterval('Rueckmeldesampler', 1000);
|
||||
$this->SetStatus(102);
|
||||
}
|
||||
|
||||
public function Destroy(): void
|
||||
{
|
||||
IPS_LogMessage('ENELIXTimerLifecycleProbe', 'Destroy entry ' . $this->InstanceID);
|
||||
// Isolated experiment only: determine whether unload can drain native timers.
|
||||
if (IPS_InstanceExists($this->InstanceID) && $this->ReadPropertyString('LifecycleMode') === 'drain') {
|
||||
$this->SetTimerInterval('Meldezyklus', 0);
|
||||
$this->SetTimerInterval('Rueckmeldesampler', 0);
|
||||
$deadline = microtime(true) + 2.5;
|
||||
do {
|
||||
$running = false;
|
||||
foreach (IPS_GetTimerList() as $id) {
|
||||
$timer = IPS_GetTimer($id);
|
||||
if ($timer['InstanceID'] === $this->InstanceID && $timer['Running']) $running = true;
|
||||
}
|
||||
if ($running) usleep(20000);
|
||||
} while ($running && microtime(true) < $deadline);
|
||||
IPS_LogMessage('ENELIXTimerLifecycleProbe', 'Destroy drain running=' . (int) $running);
|
||||
}
|
||||
parent::Destroy();
|
||||
}
|
||||
|
||||
public function Tick(string $ident): void
|
||||
{
|
||||
$this->RequestAction($ident, 0);
|
||||
}
|
||||
|
||||
public function StopProbe(): void
|
||||
{
|
||||
$this->SetTimerInterval('Meldezyklus', 0);
|
||||
$this->SetTimerInterval('Rueckmeldesampler', 0);
|
||||
}
|
||||
|
||||
public function RequestAction($Ident, $Value): void
|
||||
{
|
||||
if (!in_array($Ident, ['Read', 'Report'], true)) throw new InvalidArgumentException('Unknown probe action');
|
||||
$lock = 'ENELIX.TimerProbe.' . ($Ident === 'Read' ? 'Feedback.' : 'Battery.') . $this->InstanceID;
|
||||
if (!IPS_SemaphoreEnter($lock, 0)) return;
|
||||
try {
|
||||
usleep(max(0, min(2000, $this->ReadPropertyInteger($Ident . 'WorkMs'))) * 1000);
|
||||
$this->WriteAttributeInteger($Ident . 'Runs', $this->ReadAttributeInteger($Ident . 'Runs') + 1);
|
||||
} finally {
|
||||
IPS_SemaphoreLeave($lock);
|
||||
}
|
||||
$this->WriteAttributeInteger('CallbackEnds', $this->ReadAttributeInteger('CallbackEnds') + 1);
|
||||
}
|
||||
|
||||
public function MarkScriptEnd(): void
|
||||
{
|
||||
$this->WriteAttributeInteger('ScriptEnds', $this->ReadAttributeInteger('ScriptEnds') + 1);
|
||||
}
|
||||
|
||||
public function ReadProbeState(): string
|
||||
{
|
||||
return json_encode(['readRuns' => $this->ReadAttributeInteger('ReadRuns'),
|
||||
'callbackEnds' => $this->ReadAttributeInteger('CallbackEnds'),
|
||||
'scriptEnds' => $this->ReadAttributeInteger('ScriptEnds'),
|
||||
'reportRuns' => $this->ReadAttributeInteger('ReportRuns')], JSON_THROW_ON_ERROR);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user