feat(v4): confirm feedback with device reads
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// Execute only in Lihrenmoos Symcon. Installs confirmed reads and accepted virtual_split mapping; never starts a trial.
|
||||
if (!function_exists('IPS_GetKernelVersion')) {
|
||||
throw new RuntimeException('Nur im IP-Symcon-Skripteditor ausfuehren.');
|
||||
}
|
||||
require_once __DIR__ . '/file_installer.php';
|
||||
|
||||
$manager = 17004;
|
||||
$battery = 44234;
|
||||
$locked = false;
|
||||
$changedMapping = false;
|
||||
$oldMapping = null;
|
||||
$report = [
|
||||
'scope' => 'confirmed_feedback_trial_disabled',
|
||||
'startedAt' => gmdate('c'),
|
||||
'actuatorPermissionGranted' => false,
|
||||
'serverUpdateRequired' => true,
|
||||
'acceptedModel' => 'virtual_split',
|
||||
];
|
||||
|
||||
try {
|
||||
$hashes = json_decode((string) file_get_contents(__DIR__ . '/PACKAGE_HASHES.json'), true, 32, JSON_THROW_ON_ERROR);
|
||||
foreach ($hashes as $name => $hash) {
|
||||
if (str_contains($name, '..') || str_starts_with($name, '/') || is_link(__DIR__ . '/' . $name)
|
||||
|| hash_file('sha256', __DIR__ . '/' . $name) !== $hash) {
|
||||
throw new RuntimeException('Vorbereitetes Paket veraendert.');
|
||||
}
|
||||
}
|
||||
foreach ([
|
||||
$manager => '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
|
||||
$battery => '{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}',
|
||||
] as $id => $module) {
|
||||
if (!IPS_InstanceExists($id) || IPS_GetInstance($id)['ModuleInfo']['ModuleID'] !== $module) {
|
||||
throw new RuntimeException('Modulzuordnung ungueltig.');
|
||||
}
|
||||
if (IPS_HasChanges($id)) {
|
||||
throw new RuntimeException('Offene Aenderungen zuerst speichern oder verwerfen.');
|
||||
}
|
||||
}
|
||||
|
||||
$beforeManager = json_decode(IPS_GetConfiguration($manager), true, 128, JSON_THROW_ON_ERROR);
|
||||
$beforeBattery = json_decode(IPS_GetConfiguration($battery), true, 128, JSON_THROW_ON_ERROR);
|
||||
if (($beforeManager['NetzfahrplanAktiv'] ?? null) !== false
|
||||
|| ($beforeManager['NetzfahrplanV4RegeltestErlaubt'] ?? false) !== false
|
||||
|| ($beforeBattery['NetzfahrplanV4RegeltestErlaubt'] ?? false) !== false) {
|
||||
throw new RuntimeException('Alte Fahrplanausgabe und beide Regeltestfreigaben muessen AUS bleiben.');
|
||||
}
|
||||
|
||||
$configuration = json_decode((string) file_get_contents(__DIR__ . '/feedback-config.json'), true, 32, JSON_THROW_ON_ERROR);
|
||||
$manifest = json_decode((string) file_get_contents(__DIR__ . '/MANIFEST.json'), true, 32, JSON_THROW_ON_ERROR);
|
||||
if (($configuration['managerId'] ?? null) !== $manager
|
||||
|| ($configuration['batteryInstanceId'] ?? null) !== $battery
|
||||
|| ($configuration['mode'] ?? null) !== 'virtual_split'
|
||||
|| ($configuration['allowEstimatedForTrial'] ?? null) !== true
|
||||
|| hash_file('sha256', __DIR__ . '/feedback-config.json') !== $manifest['configurationSha256']) {
|
||||
throw new RuntimeException('Falsche Rueckmeldekonfiguration.');
|
||||
}
|
||||
$desired = json_encode($configuration, JSON_THROW_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION);
|
||||
$previousConfiguration = $configuration;
|
||||
$previousConfiguration['allowEstimatedForTrial'] = false;
|
||||
$previousDesired = json_encode($previousConfiguration, JSON_THROW_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION);
|
||||
$oldMapping = $beforeBattery['NetzfahrplanV4RueckmeldungKonfiguration'] ?? '{}';
|
||||
if (!in_array($oldMapping, [$previousDesired, $desired], true)) {
|
||||
throw new RuntimeException('Abweichende Rueckmeldekonfiguration nicht ueberschrieben.');
|
||||
}
|
||||
|
||||
$controls = [];
|
||||
foreach (IPS_GetModuleList() as $module) {
|
||||
if ((IPS_GetModule($module)['Prefix'] ?? '') === 'MC') {
|
||||
$controls = array_merge($controls, IPS_GetInstanceListByModuleID($module));
|
||||
}
|
||||
}
|
||||
if (count($controls) !== 1 || !function_exists('MC_ReloadModule')) {
|
||||
throw new RuntimeException('Module Control nicht eindeutig.');
|
||||
}
|
||||
$locked = IPS_SemaphoreEnter('ENELIX.V4.ConfirmedFeedbackInstall', 3000);
|
||||
if (!$locked) {
|
||||
throw new RuntimeException('Installation bereits aktiv.');
|
||||
}
|
||||
|
||||
$report['files'] = v4ConfirmedFiles(__DIR__, '/var/lib/symcon/modules/Enelix-EMS');
|
||||
if (MC_ReloadModule($controls[0], 'Enelix-EMS') === false) {
|
||||
throw new RuntimeException('Bibliotheks-Reload fehlgeschlagen.');
|
||||
}
|
||||
|
||||
$afterManager = json_decode(IPS_GetConfiguration($manager), true, 128, JSON_THROW_ON_ERROR);
|
||||
$afterBattery = json_decode(IPS_GetConfiguration($battery), true, 128, JSON_THROW_ON_ERROR);
|
||||
foreach ([[$beforeManager, $afterManager], [$beforeBattery, $afterBattery]] as $pair) {
|
||||
foreach ($pair[0] as $key => $value) {
|
||||
if (!array_key_exists($key, $pair[1]) || $pair[1][$key] !== $value) {
|
||||
throw new RuntimeException('Bestehender Parameter beim Reload veraendert: ' . $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('ENELIX_GetV4BatterieRueckmeldung')) {
|
||||
$report['status'] = 'waiting_for_registration';
|
||||
echo "Dateien installiert. Modulregistrierung wird abgeschlossen; diesen Aufruf einmal wiederholen. Keine Stellfreigabe.\n";
|
||||
} else {
|
||||
if ($afterBattery['NetzfahrplanV4RueckmeldungKonfiguration'] !== $desired) {
|
||||
IPS_SetProperty($battery, 'NetzfahrplanV4RueckmeldungKonfiguration', $desired);
|
||||
$changedMapping = true;
|
||||
IPS_ApplyChanges($battery);
|
||||
}
|
||||
$finalManager = json_decode(IPS_GetConfiguration($manager), true, 128, JSON_THROW_ON_ERROR);
|
||||
$finalBattery = json_decode(IPS_GetConfiguration($battery), true, 128, JSON_THROW_ON_ERROR);
|
||||
foreach ([[$beforeManager, $finalManager], [$beforeBattery, $finalBattery]] as $pair) {
|
||||
foreach ($pair[0] as $key => $value) {
|
||||
if ($key !== 'NetzfahrplanV4RueckmeldungKonfiguration'
|
||||
&& (!array_key_exists($key, $pair[1]) || $pair[1][$key] !== $value)) {
|
||||
throw new RuntimeException('Bestehender Parameter unerwartet veraendert: ' . $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($finalManager['NetzfahrplanAktiv'] ?? null) !== false
|
||||
|| ($finalManager['NetzfahrplanV4RegeltestErlaubt'] ?? null) !== false
|
||||
|| ($finalBattery['NetzfahrplanV4RegeltestErlaubt'] ?? null) !== false) {
|
||||
throw new RuntimeException('Unerwartete Stellfreigabe nach Installation.');
|
||||
}
|
||||
|
||||
$feedback = json_decode(ENELIX_GetV4BatterieRueckmeldung($battery), true, 32, JSON_THROW_ON_ERROR);
|
||||
$report['feedback'] = array_intersect_key($feedback, array_flip([
|
||||
'status', 'kind', 'method', 'reason', 'reasons', 'estimated', 'batteryW', 'gridW',
|
||||
'sourceOldestAt', 'sourceVariableOldestAt', 'confirmedAt', 'checkedAt', 'configHash',
|
||||
'deviceReadConfirmed', 'usableForTrial', 'canDispatch',
|
||||
]));
|
||||
$report['status'] = 'confirmed_feedback_installed_trial_disabled';
|
||||
$report['originalParametersPreserved'] = true;
|
||||
echo "OK: Geraeteabfrage bestaetigt die physischen Messwerte; virtual_split ist fuer den begrenzten Regeltest akzeptiert.\n";
|
||||
echo 'Rueckmeldung: ' . ($feedback['status'] ?? 'available')
|
||||
. '; Geraeteabfrage: ' . (($feedback['deviceReadConfirmed'] ?? false) ? 'bestaetigt' : 'nicht bestaetigt')
|
||||
. '; Modellanteil: ' . (($feedback['estimated'] ?? false) ? 'ja' : 'nein') . ".\n";
|
||||
if (isset($feedback['reason'])) {
|
||||
echo 'Aktueller Hinweis: ' . $feedback['reason'] . "\n";
|
||||
}
|
||||
echo "Beide Regeltestfreigaben AUS. Kein Stellbefehl ohne separat nachgewiesenen Geraete-Watchdog und Serverfreigabe.\n";
|
||||
}
|
||||
} catch (Throwable $error) {
|
||||
$report['status'] = 'needs_review';
|
||||
$report['reason'] = substr($error->getMessage(), 0, 260);
|
||||
if ($changedMapping && $oldMapping !== null) {
|
||||
try {
|
||||
IPS_SetProperty($battery, 'NetzfahrplanV4RueckmeldungKonfiguration', $oldMapping);
|
||||
IPS_ApplyChanges($battery);
|
||||
$report['mappingRestored'] = true;
|
||||
} catch (Throwable $ignored) {
|
||||
$report['mappingRestored'] = false;
|
||||
}
|
||||
}
|
||||
echo 'FEHLER: ' . $report['reason'] . "\nKeine V4-Stellfreigabe erteilt.\n";
|
||||
} finally {
|
||||
$report['finishedAt'] = gmdate('c');
|
||||
v4ConfirmedWrite(__DIR__ . '/INSTALL_RESULT.json', json_encode($report, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT) . "\n", 0644);
|
||||
if ($locked) {
|
||||
IPS_SemaphoreLeave('ENELIX.V4.ConfirmedFeedbackInstall');
|
||||
}
|
||||
echo 'CONFIRMED FEEDBACK INSTALL REPORT: ' . __DIR__ . "/INSTALL_RESULT.json\n";
|
||||
}
|
||||
Reference in New Issue
Block a user