feat(energy-pie): finish configurable colors and Symcon 8 migration
Tests / test (push) Waiting to run

This commit is contained in:
dh
2026-10-07 17:16:00 +00:00
parent 5b6125d086
commit 2ce95e77f8
7 changed files with 376 additions and 37 deletions
+26 -5
View File
@@ -37,10 +37,29 @@ final class EnergiediagrammModulstrukturTest extends TestCase
'Standardzeitraum',
'FarbeEigenverbrauch',
'FarbeAutarkie',
'FarbeHintergrund',
'FarbeHintergrundAkzent1',
'FarbeHintergrundAkzent2',
] as $property) {
self::assertStringContainsString($property, $serialized);
}
self::assertSame(2, substr_count($serialized, 'SelectColor'));
self::assertSame(5, substr_count($serialized, 'SelectColor'));
$colors = [];
$walk = static function (array $elements) use (&$walk, &$colors): void {
foreach ($elements as $element) {
if ($element['type'] === 'SelectColor') {
$colors[] = $element;
}
if (isset($element['items'])) {
$walk($element['items']);
}
}
};
$walk($form['elements']);
foreach ($colors as $color) {
self::assertStringEndsWith('RGB', $color['name']);
self::assertFalse($color['allowTransparent']);
}
}
public function testHtmlStartsWithDataAndRespondsToAvailableWidth(): void
@@ -54,7 +73,7 @@ final class EnergiediagrammModulstrukturTest extends TestCase
self::assertStringContainsString('padding: 58px 10px 10px', $html);
self::assertStringContainsString('background-color: var(--card-color, transparent)', $html);
self::assertStringContainsString('color: var(--content-color, CanvasText)', $html);
self::assertStringContainsString('function syncColorScheme()', $html);
self::assertStringContainsString('function syncBackground(colors)', $html);
self::assertStringContainsString('SetCustomRange', $html);
self::assertStringNotContainsString("addEventListener('load'", $html);
}
@@ -71,15 +90,17 @@ final class EnergiediagrammModulstrukturTest extends TestCase
foreach ([
'inset: 0',
'z-index: -1',
'radial-gradient(520px 420px at 18% 18%, rgba(99, 179, 255, 0.42), transparent 60%)',
'radial-gradient(560px 460px at 82% 28%, rgba(168, 85, 247, 0.38), transparent 62%)',
'radial-gradient(620px 520px at 55% 85%, rgba(99, 179, 255, 0.26), transparent 64%)',
'radial-gradient(520px 420px at 18% 18%, rgba(var(--background-accent-1-rgb), 0.42), transparent 60%)',
'radial-gradient(560px 460px at 82% 28%, rgba(var(--background-accent-2-rgb), 0.38), transparent 62%)',
'radial-gradient(620px 520px at 55% 85%, rgba(var(--background-accent-1-rgb), 0.26), transparent 64%)',
'filter: blur(18px)',
'pointer-events: none',
] as $style) {
self::assertStringContainsString($style, $background[1]);
}
self::assertStringContainsString('overflow: auto', $html);
self::assertStringContainsString('--background-accent-1-rgb: 99, 179, 255;', $html);
self::assertStringContainsString('--background-accent-2-rgb: 168, 85, 247;', $html);
self::assertStringNotContainsString('touch-action: none', $html);
}
+59 -1
View File
@@ -12,6 +12,9 @@ function visualization(initialState) {
if (!elements.has(id)) {
elements.set(id, {
innerHTML: '', textContent: '', value: '', hidden: false,
style: {
setProperty(name, value) { this[name] = value; }
},
addEventListener() {}, classList: { toggle() {} }
});
}
@@ -30,7 +33,7 @@ function visualization(initialState) {
window, document,
getComputedStyle: () => ({ getPropertyValue: () => '' })
});
return { element, window };
return { element, window, document };
}
function payload(overrides = {}) {
@@ -86,3 +89,58 @@ test('missing archive values do not hide the attribution limitation', () => {
assert.equal(ui.element('message').textContent,
'No archive data. Different measurement boundaries.');
});
test('old payloads retain the original Energy Pie background', () => {
const ui = visualization(payload());
const style = ui.element('energy-app').style;
assert.equal(style['--card-color'], '#121216');
assert.equal(style['--background-accent-1-rgb'], '99, 179, 255');
assert.equal(style['--background-accent-2-rgb'], '168, 85, 247');
assert.equal(style['--content-color'], '#f5f5f7');
assert.equal(style.colorScheme, 'dark');
});
test('configured backgrounds apply initially and on visualization updates', () => {
const ui = visualization(payload({ colors: {
background: '#FFFFFF', backgroundAccent1: '#DCE169', backgroundAccent2: '#4E8181',
selfConsumption: '#1259A7', autarky: '#178A55'
} }));
const style = ui.element('energy-app').style;
assert.equal(style['--card-color'], '#FFFFFF');
assert.equal(style['--background-accent-1-rgb'], '220, 225, 105');
assert.equal(style['--background-accent-2-rgb'], '78, 129, 129');
assert.equal(style['--content-color'], '#121216');
assert.equal(style.colorScheme, 'light');
assert.equal(ui.document.documentElement.style.colorScheme, undefined);
const state = payload({ colors: {
background: '#000000', backgroundAccent1: '#112233', backgroundAccent2: '#445566',
selfConsumption: '#1259A7', autarky: '#178A55'
} });
state.values.Eigenverbrauchsquote = 75;
state.values.Autarkiegrad = 50;
ui.window.handleMessage(JSON.stringify(state));
assert.equal(style['--card-color'], '#000000');
assert.equal(style['--background-accent-1-rgb'], '17, 34, 51');
assert.equal(style['--background-accent-2-rgb'], '68, 85, 102');
assert.equal(style['--content-color'], '#f5f5f7');
assert.equal(style.colorScheme, 'dark');
assert.match(ui.element('self-consumption-chart').innerHTML, /stroke="#1259A7"/);
assert.match(ui.element('autarky-chart').innerHTML, /stroke="#178A55"/);
ui.window.handleMessage(payload());
assert.equal(style['--card-color'], '#121216');
assert.equal(style['--background-accent-1-rgb'], '99, 179, 255');
});
test('invalid or incomplete background colors fall back independently', () => {
for (const invalid of [null, -1, 16777216, {}, '', '#123', '#123456; color:red', 'url(https://invalid.test/)']) {
const ui = visualization(payload({ hasData: false, colors: {
background: invalid, backgroundAccent1: '#aAbBcC', backgroundAccent2: invalid
} }));
const style = ui.element('energy-app').style;
assert.equal(style['--card-color'], '#121216');
assert.equal(style['--background-accent-1-rgb'], '170, 187, 204');
assert.equal(style['--background-accent-2-rgb'], '168, 85, 247');
}
});
+90
View File
@@ -29,6 +29,14 @@ return static function (TestContext $test): void {
$test->assertSame('month', IPS_GetProperty($moduleId, 'Standardzeitraum'));
$test->assertSame('#1259A7', IPS_GetProperty($moduleId, 'FarbeEigenverbrauch'));
$test->assertSame('#178A55', IPS_GetProperty($moduleId, 'FarbeAutarkie'));
$test->assertSame('#121216', IPS_GetProperty($moduleId, 'FarbeHintergrund'));
$test->assertSame('#63B3FF', IPS_GetProperty($moduleId, 'FarbeHintergrundAkzent1'));
$test->assertSame('#A855F7', IPS_GetProperty($moduleId, 'FarbeHintergrundAkzent2'));
$test->assertSame(0x1259A7, IPS_GetProperty($moduleId, 'FarbeEigenverbrauchRGB'));
$test->assertSame(0x178A55, IPS_GetProperty($moduleId, 'FarbeAutarkieRGB'));
$test->assertSame(0x121216, IPS_GetProperty($moduleId, 'FarbeHintergrundRGB'));
$test->assertSame(0x63B3FF, IPS_GetProperty($moduleId, 'FarbeHintergrundAkzent1RGB'));
$test->assertSame(0xA855F7, IPS_GetProperty($moduleId, 'FarbeHintergrundAkzent2RGB'));
});
$test->runCase('Konfigurationsformular ist gültiges JSON', static function (
@@ -58,4 +66,86 @@ return static function (TestContext $test): void {
IPS_RequestAction($moduleId, 'Refresh', true);
$test->assertSame(102, (int) IPS_GetInstance($moduleId)['InstanceStatus']);
});
$test->runCase('Hintergrundfarben akzeptieren Hex- und Symcon-8-Farbwerte', static function (
TestContext $test
) use ($moduleId): void {
$colors = [
'FarbeHintergrund' => '#FFFFFF',
'FarbeHintergrundAkzent1' => '0',
'FarbeHintergrundAkzent2' => '16777215',
];
$test->configureInstance($moduleId, $colors);
$test->assertInstanceStatus($moduleId);
foreach ($colors as $property => $color) {
$test->assertSame($color, IPS_GetProperty($moduleId, $property));
}
});
$test->runCase('Ungueltige Hintergrundfarben werden abgewiesen', static function (
TestContext $test
) use ($moduleId): void {
foreach (['FarbeHintergrund', 'FarbeHintergrundAkzent1', 'FarbeHintergrundAkzent2'] as $property) {
$original = IPS_GetProperty($moduleId, $property);
try {
$test->configureInstance($moduleId, [$property => 'not-a-color']);
$test->assertInstanceStatus($moduleId, 201);
} finally {
$test->configureInstance($moduleId, [$property => $original]);
}
$test->assertInstanceStatus($moduleId);
}
});
$test->runCase('Jede Farbauswahl speichert nur die geaenderte Farbe', static function (
TestContext $test
) use ($moduleId): void {
$properties = ['FarbeEigenverbrauch', 'FarbeAutarkie', 'FarbeHintergrund',
'FarbeHintergrundAkzent1', 'FarbeHintergrundAkzent2'];
foreach ($properties as $index => $property) {
$before = json_decode(IPS_GetConfiguration($moduleId), true, 512, JSON_THROW_ON_ERROR);
$rgb = [0xABCDEF, 0x000001, 0, 0xFFFFFF, 0x12AB34][$index];
$test->configureInstance($moduleId, [$property . 'RGB' => $rgb]);
$test->assertInstanceStatus($moduleId);
foreach ($properties as $other) {
$test->assertSame($other === $property ? $rgb : $before[$other . 'RGB'],
IPS_GetProperty($moduleId, $other . 'RGB'));
$test->assertSame($other === $property ? sprintf('#%06X', $rgb) : $before[$other],
IPS_GetProperty($moduleId, $other));
}
}
$before = json_decode(IPS_GetConfiguration($moduleId), true, 512, JSON_THROW_ON_ERROR);
$test->configureInstance($moduleId, ['Aktualisierungsintervall' => 120]);
IPS_ApplyChanges($moduleId);
foreach ($properties as $property) {
$test->assertSame($before[$property], IPS_GetProperty($moduleId, $property));
$test->assertSame($before[$property . 'RGB'], IPS_GetProperty($moduleId, $property . 'RGB'));
}
});
$test->runCase('Alte Farbschnittstelle bleibt mit der Farbauswahl synchron', static function (
TestContext $test
) use ($moduleId): void {
foreach (['#000001' => 1, '11259375' => 0xABCDEF, '0' => 0] as $legacy => $rgb) {
$test->configureInstance($moduleId, ['FarbeHintergrund' => (string) $legacy]);
$test->assertSame($rgb, IPS_GetProperty($moduleId, 'FarbeHintergrundRGB'));
$test->assertSame((string) $legacy, IPS_GetProperty($moduleId, 'FarbeHintergrund'));
}
$test->configureInstance($moduleId, [
'FarbeHintergrund' => '#123456', 'FarbeHintergrundRGB' => 0x987654,
]);
$test->assertSame('#987654', IPS_GetProperty($moduleId, 'FarbeHintergrund'));
$test->assertSame(0x987654, IPS_GetProperty($moduleId, 'FarbeHintergrundRGB'));
});
$test->runCase('Ungueltige numerische Farbauswahl wird abgewiesen', static function (
TestContext $test
) use ($moduleId): void {
foreach ([-1, 0x1000000] as $invalid) {
$test->configureInstance($moduleId, ['FarbeHintergrundRGB' => $invalid]);
$test->assertInstanceStatus($moduleId, 201);
}
$test->configureInstance($moduleId, ['FarbeHintergrundRGB' => 0x121216]);
$test->assertInstanceStatus($moduleId);
});
};