$row['Typ'] . $row['Kanal'], $selection )) ); self::assertSame([], array_filter( $selection, static fn (array $row): bool => $row['Aktiv'] )); } public function testSelectionNormalizesNamesAndIntervals(): void { $selection = CC100ChannelModel::normalizeSelection(json_encode([ [ 'Aktiv' => true, 'Typ' => 'di', 'Kanal' => 1, 'Anzeigename' => '', 'Abfrageintervall' => 250, ], [ 'Aktiv' => true, 'Typ' => 'AO', 'Kanal' => 2, 'Anzeigename' => 'Ventil', 'Abfrageintervall' => 5000, ], ], JSON_THROW_ON_ERROR)); self::assertSame('DI1', $selection[0]['key']); self::assertSame('Digitaler Eingang 1', $selection[0]['name']); self::assertSame(250, $selection[0]['pollInterval']); self::assertSame('AO2', $selection[1]['key']); self::assertSame('Ventil', $selection[1]['name']); } public function testDuplicateChannelIsRejected(): void { $this->expectException(InvalidArgumentException::class); CC100ChannelModel::normalizeSelection(json_encode([ ['Typ' => 'DI', 'Kanal' => 1, 'Abfrageintervall' => 500], ['Typ' => 'DI', 'Kanal' => 1, 'Abfrageintervall' => 500], ], JSON_THROW_ON_ERROR)); } public function testCalibrationSupportsWagoAZeroOneHeaderAndBothDirections(): void { $calibration = CC100ChannelModel::parseCalibration( "AI1 A01\n100 0 1100 10000\n200 0 1200 10000\n" ); self::assertArrayHasKey('AO1', $calibration); self::assertSame(5000.0, CC100ChannelModel::rawToEngineering(600, $calibration['AI1'])); self::assertSame(700, CC100ChannelModel::engineeringToRaw(5000, $calibration['AO1'])); } public function testPt1000CurveAndBitOperationsAreStable(): void { self::assertSame(0.0, CC100ChannelModel::pt1000Temperature(1000.0)); self::assertEqualsWithDelta(100.0, CC100ChannelModel::pt1000Temperature(1385.05), 0.1); self::assertTrue(CC100ChannelModel::bitState(5, 1)); self::assertFalse(CC100ChannelModel::bitState(5, 2)); self::assertTrue(CC100ChannelModel::bitState(5, 3)); self::assertSame(7, CC100ChannelModel::withBitState(5, 2, true)); self::assertSame(4, CC100ChannelModel::withBitState(5, 1, false)); } }