90 lines
5.6 KiB
PHP
90 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/runtime.php';
|
|
|
|
/** Creates ONLY dedicated capture objects. No module reload, device settings or archives. */
|
|
function v4captureEnsure(int $parent, string $ident, int $type, string $name, string $marker, array &$created): int
|
|
{
|
|
$existing = v4captureChild($parent, $ident);
|
|
if ($existing !== null) {
|
|
v4captureAssertObject($existing, $parent, $ident, $type, $marker);
|
|
return $existing;
|
|
}
|
|
$id = match ($type) { 0 => IPS_CreateCategory(), 2 => IPS_CreateVariable(3), 3 => IPS_CreateScript(0) };
|
|
if (!is_int($id) || $id <= 0) throw new RuntimeException('Cannot create capture object');
|
|
$created[] = $id;
|
|
if (!IPS_SetParent($id, $parent) || !IPS_SetIdent($id, $ident) || !IPS_SetName($id, $name) || !IPS_SetInfo($id, $marker)) {
|
|
throw new RuntimeException('Cannot label capture object');
|
|
}
|
|
return $id;
|
|
}
|
|
|
|
function v4captureScript(int $id, string $content, array $created): void
|
|
{
|
|
$current = IPS_GetScriptContent($id);
|
|
if ($current === $content) return;
|
|
if (!in_array($id, $created, true)) throw new RuntimeException('Existing capture script changed; not overwritten');
|
|
if (!IPS_SetScriptContent($id, $content) || IPS_GetScriptContent($id) !== $content) throw new RuntimeException('Cannot store capture script');
|
|
}
|
|
|
|
function v4captureInstall(string $stage): array
|
|
{
|
|
if (!function_exists('IPS_GetKernelVersion') || version_compare(IPS_GetKernelVersion(),'8.0','<')) {
|
|
throw new RuntimeException('Nur im IP-Symcon-Skripteditor der Testanlage ausfuehren.');
|
|
}
|
|
$c = v4captureConfig($stage); $marker = v4captureMarker($c);
|
|
if (!IPS_InstanceExists($c['managerId'])
|
|
|| IPS_GetInstance($c['managerId'])['ModuleInfo']['ModuleID'] !== '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}') {
|
|
throw new RuntimeException('Expected manager not found');
|
|
}
|
|
// Verify layout only; stale/missing sensor updates remain diagnostic raw data, not fake zeros.
|
|
foreach (array_merge($c['accounting']['sources'], $c['extraSources']) as $s) {
|
|
if (!IPS_VariableExists($s['variableId'])) throw new RuntimeException('Expected source missing: ' . $s['key']);
|
|
$o = IPS_GetObject($s['variableId']); $v = IPS_GetVariable($s['variableId']);
|
|
if ($o['ParentID'] !== $s['parentId'] || $o['ObjectIdent'] !== $s['ident'] || !in_array($v['VariableType'],[1,2],true)) {
|
|
throw new RuntimeException('Source identity changed: ' . $s['key']);
|
|
}
|
|
}
|
|
$data = $stage . '/data';
|
|
if (is_link($data) || !is_dir($data) || !is_writable($data)) throw new RuntimeException('Dedicated capture directory not writable');
|
|
$key = 'ENELIX.V4.CaptureInstall.' . $c['installationId'];
|
|
if (!IPS_SemaphoreEnter($key, 3000)) throw new RuntimeException('Capture installation busy');
|
|
$created = []; $script = null; $timerSet = false;
|
|
$report = ['startedAt' => gmdate('c'), 'scope' => 'passive_raw_capture_only', 'controlEnabled' => false,
|
|
'existingModulesChanged' => false, 'archivesChanged' => false, 'existingHistoriesChanged' => false];
|
|
try {
|
|
$category = v4captureEnsure(0,'ENELIX_V4_PASSIVE_CAPTURE',0,'V4 - separate Messaufnahme (keine Steuerung)',$marker,$created);
|
|
v4captureEnsure($category,'CaptureStatus',2,'Aufzeichnungsstatus (nur lesen)',$marker,$created);
|
|
$script = v4captureEnsure($category,'RawCapture',3,'Messwerte alle 30 Sekunden erfassen',$marker,$created);
|
|
$stop = v4captureEnsure($category,'StopCapture',3,'Nur diese Messaufnahme stoppen',$marker,$created);
|
|
$include = '<?php' . "\n" . 'require_once ' . var_export($stage . '/source/examples/V4DataCapture/runtime.php',true) . ';' . "\n";
|
|
v4captureScript($script, $include . 'v4captureRun(' . var_export($stage,true) . ', ' . $category . ');' . "\n", $created);
|
|
v4captureScript($stop, $include . 'v4captureStop(' . var_export($stage,true) . ', ' . $category . ');' . "\n", $created);
|
|
$first = v4captureRun($stage, $category);
|
|
if ($first['status'] !== 'recorded') throw new RuntimeException('Capture not stored: ' . ($first['reason'] ?? $first['status']));
|
|
// This new timer never invokes a manager, gateway, battery or Modbus function.
|
|
if (!IPS_SetScriptTimer($script, 30)) throw new RuntimeException('Cannot start dedicated capture timer');
|
|
$timerSet = true;
|
|
$report += ['status' => 'capture_installed', 'categoryId' => $category, 'scriptId' => $script,
|
|
'stopScriptId' => $stop, 'intervalSeconds' => 30, 'firstCapture' => $first,
|
|
'futureTimerExecutionVerified' => false];
|
|
echo "OK: Separate Rohdatenaufnahme eingerichtet, alle 30 Sekunden.\n";
|
|
echo 'Erste Aufnahme: ' . $first['capturedAt'] . '; Quellen: ' . $first['sourceCount'] . ".\n";
|
|
echo 'Bilanzqualitaet: ' . $first['accountingQuality'] . " (noch keine Trainings-/Stellfreigabe).\n";
|
|
echo "Bestehende Manager-, Batterie-, Archiv- und Pollingkonfiguration unveraendert.\n";
|
|
} catch (Throwable $e) {
|
|
$report['status'] = 'needs_review'; $report['reason'] = substr($e->getMessage(),0,300);
|
|
if ($timerSet && $script !== null) IPS_SetScriptTimer($script,0);
|
|
// Never delete unrelated objects or stored data during recovery.
|
|
echo 'FEHLER: ' . $report['reason'] . "\n";
|
|
} finally {
|
|
$report['createdObjects'] = $created; $report['finishedAt'] = gmdate('c');
|
|
try { v4captureAtomicJson($stage . '/INSTALL_RESULT.json', $report); }
|
|
finally { IPS_SemaphoreLeave($key); }
|
|
echo 'CAPTURE REPORT: ' . $stage . "/INSTALL_RESULT.json\n";
|
|
}
|
|
return $report;
|
|
}
|