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 = ' '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; }