feat(workflow): publish verified forecast controls and consolidated docs
Tests / test (push) Successful in 1m1s

Approved by Daniel Haefliger for develop and beta. Author dh_Agent, authenticated account dh. Preserve published battery, charging and overall Energy Pie changes. No deployment or plant control authorization.
This commit is contained in:
dh
2026-10-08 10:02:58 +00:00
parent af69151165
commit 74a2d6c685
82 changed files with 5054 additions and 617 deletions
+9 -4
View File
@@ -13,21 +13,23 @@ namespace Belevo\EnelixEMS {
class FeedbackReceiver {
use ManagerNetzfahrplanV4EmpfangTrait;
public int $InstanceID=17004;public array $props,$attrs,$op;
public function __construct($r,$op){$this->op=$op;$this->props=['NetzfahrplanV4EmpfangAktiv'=>true,'NetzfahrplanV4SchattenAktiv'=>true,'NetzfahrplanAktiv'=>false,'MesswertMaxAlter'=>60,'AnlagenBatterien'=>json_encode([['ID'=>'b','LeistungVariableID'=>1002,'SOCVariableID'=>1001,'Leistungsfaktor'=>1]])];$this->attrs=['LizenzInstallationID'=>$r['installationId'],'NetzfahrplanV4Empfang'=>json_encode(['response'=>$r,'receivedAt'=>time()]),'NetzfahrplanV4EmpfangStatus'=>'{}'];}
public function __construct($r,$op){$this->op=$op;$this->props=['PrognoseAktiv'=>true,'NetzfahrplanRegelungAktiv'=>false,'NetzfahrplanV4SchattenAktiv'=>true,'NetzfahrplanAktiv'=>false,'MesswertMaxAlter'=>60,'AnlagenBatterien'=>json_encode([['ID'=>'b','LeistungVariableID'=>1002,'SOCVariableID'=>1001,'Leistungsfaktor'=>1]])];$this->attrs=['LizenzInstallationID'=>$r['installationId'],'NetzfahrplanV4Empfang'=>json_encode(['response'=>$r,'receivedAt'=>time()]),'NetzfahrplanV4EmpfangStatus'=>'{}','PrognoseV4Serverstatus'=>'{}'];}
private function ReadPropertyBoolean($k){return $this->props[$k];}
private function ReadPropertyString($k){return $this->props[$k];}
private function ReadPropertyInteger($k){return $this->props[$k];}
private function ReadAttributeString($k){return $this->attrs[$k];}
private function aktiveVerbraucherIDs(){return [44234];}
private function prognoseLernenAktiv(){return $this->props['PrognoseAktiv'];}
private function berechtigungLizenziert($k){return true;}
public function GetNetzfahrplanV4Diagnose(){return json_encode(['operation'=>$this->op]);}
}
}
namespace {
function ENELIX_GetV4BatterieRueckmeldung($id){$GLOBALS['now']+=($GLOBALS['feedbackDelay']??0);$GLOBALS['feedback']['checkedAt']=$GLOBALS['now'];return json_encode($GLOBALS['feedback']);}
function ENELIX_GetV4BatterieRueckmeldungCache($id){$GLOBALS['cacheReads']++;$GLOBALS['now']+=($GLOBALS['feedbackDelay']??0);return json_encode($GLOBALS['feedback']);}
function ENELIX_GetV4BatterieRueckmeldung($id){throw new RuntimeException('Synchronous device read forbidden in preview');}
require_once __DIR__.'/../V4Receiver/fixture.php';
use Belevo\EnelixEMS\FeedbackReceiver;
[$response,$id,$op,$now]=receiverFixture();$configured=true;$count=0;$feedbackDelay=0;
[$response,$id,$op,$now]=receiverFixture();$configured=true;$count=0;$feedbackDelay=0;$cacheReads=0;
$feedback=['kind'=>'local_physical_feedback','version'=>1,'installationId'=>$id,'assetId'=>'b','managerId'=>17004,'batteryInstanceId'=>44234,'batteryW'=>0.,'gridW'=>$op['gridW'],'checkedAt'=>$now,'estimated'=>true,'usableForTrial'=>false,'canDispatch'=>false,'configHash'=>str_repeat('a',64)];
function ck($v,$t){global$count;if(!$v)throw new RuntimeException('FAIL '.$t);$count++;echo "PASS $t\n";}
$m=new FeedbackReceiver($response,$op);$p=json_decode($m->GetNetzfahrplanV4Vorschau(),true);
@@ -35,7 +37,10 @@ namespace {
ck($p['previewBatteryW']==3000,'net target translated once to total battery demand');
ck($p['canDispatch']===false&&$p['localFeedback']['b']['estimated']===true,'model feedback remains marked and preview grants no dispatch');
$feedbackDelay=1;$p=json_decode($m->GetNetzfahrplanV4Vorschau(),true);$feedbackDelay=0;
ck($p['status']==='preview_only','feedback timestamp produced after device read is compared with post-read clock');
ck($p['status']==='preview_only'&&$feedback['checkedAt']===$now-1,'cached feedback timestamp is retained across delayed preview read');
ck($cacheReads===2,'preview only reads confirmed feedback cache, never synchronous device getter');
$now+=2;$p=json_decode($m->GetNetzfahrplanV4Vorschau(),true);$now-=2;
ck($p['status']==='unavailable'&&$p['previewBatteryW']===null,'stale confirmed cache is rejected without a synchronous refresh or legacy fallback');
$feedback=['status'=>'unavailable','reason'=>'feedback_device_read_failed:grid','batteryW'=>null,'gridW'=>null];$p=json_decode($m->GetNetzfahrplanV4Vorschau(),true);
ck($p['status']==='unavailable'&&$p['previewBatteryW']===null,'configured feedback failure never falls back to held virtual display');
ck(str_contains($p['reason'],'feedback_unavailable:feedback_device_read_failed:grid'),'configured feedback exposes bounded root cause without credentials');