Fixed performance
This commit is contained in:
parent
5f13dc83b6
commit
0ae1bdf76b
@ -70,8 +70,8 @@ final class CalendarController extends AbstractController
|
||||
$icsContent = $this->calendarExportService->generateIcsContent($days, $entityHistory, $absences);
|
||||
|
||||
$response = new Response($icsContent);
|
||||
//$response->headers->set('Content-Type', 'text/calendar; charset=utf-8');
|
||||
//$response->headers->set('Content-Disposition', 'attachment; filename="work_calendar.ics"');
|
||||
$response->headers->set('Content-Type', 'text/calendar; charset=utf-8');
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="work_calendar.ics"');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core\Services\Home;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface HomeEntityInterface
|
||||
{
|
||||
public function getId(): string;
|
||||
|
||||
public function getState(): mixed;
|
||||
|
||||
public function getName(): string;
|
||||
|
||||
public function getType(): HomeEntityType;
|
||||
|
||||
public function getLastChanged(): DateTimeImmutable;
|
||||
|
||||
public function getLastUpdated(): DateTimeImmutable;
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core\Services\Home;
|
||||
|
||||
interface HomeServiceInterface
|
||||
{
|
||||
public function findEntity(string $entityId): HomeEntityInterface;
|
||||
|
||||
public function findAllEntities(): array;
|
||||
|
||||
public function callService(string $service, array $data = []): array;
|
||||
}
|
||||
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace App\HomeAssistant;
|
||||
|
||||
use function explode;
|
||||
use function in_array;
|
||||
|
||||
final readonly class EntityState
|
||||
{
|
||||
@ -30,17 +29,6 @@ final readonly class EntityState
|
||||
$data['context'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isOn(): bool
|
||||
{
|
||||
return in_array($this->state, ['on', 'home', 'open', 'unlocked', 'active'], true);
|
||||
}
|
||||
|
||||
public function isOff(): bool
|
||||
{
|
||||
return in_array($this->state, ['off', 'away', 'closed', 'locked', 'inactive'], true);
|
||||
}
|
||||
|
||||
public function getDomain(): string
|
||||
{
|
||||
$parts = explode('.', $this->entityId, 2);
|
||||
|
||||
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace App\HomeAssistant;
|
||||
|
||||
use DateTimeInterface;
|
||||
use function explode;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
@ -29,11 +28,6 @@ final readonly class HomeAssistantClient
|
||||
return $this->request('GET', '/api/states');
|
||||
}
|
||||
|
||||
public function getServices(): array
|
||||
{
|
||||
return $this->request('GET', '/api/services');
|
||||
}
|
||||
|
||||
public function getEntityState(string $entityId): array
|
||||
{
|
||||
return $this->request('GET', "/api/states/{$entityId}");
|
||||
@ -49,25 +43,6 @@ final readonly class HomeAssistantClient
|
||||
return $this->request('GET', "/api/history/period/{$startDate->format('Y-m-d\TH:i:s\Z')}?{$queryParams}")[0];
|
||||
}
|
||||
|
||||
public function callService(string $domain, string $service, array $data = []): array
|
||||
{
|
||||
return $this->request('POST', "/api/services/{$domain}/{$service}", $data);
|
||||
}
|
||||
|
||||
public function turnOn(string $entityId): array
|
||||
{
|
||||
$domain = explode('.', $entityId)[0];
|
||||
|
||||
return $this->callService($domain, 'turn_on', ['entity_id' => $entityId]);
|
||||
}
|
||||
|
||||
public function turnOff(string $entityId): array
|
||||
{
|
||||
$domain = explode('.', $entityId)[0];
|
||||
|
||||
return $this->callService($domain, 'turn_off', ['entity_id' => $entityId]);
|
||||
}
|
||||
|
||||
private function request(string $method, string $endpoint, array $data = []): array
|
||||
{
|
||||
$options = [
|
||||
|
||||
@ -4,64 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\HomeAssistant;
|
||||
|
||||
use App\Core\Services\Home\HomeEntityInterface;
|
||||
use App\Core\Services\Home\HomeEntityType;
|
||||
use App\Core\Services\Home\HomeServiceInterface;
|
||||
|
||||
use function array_filter;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function explode;
|
||||
use function str_contains;
|
||||
|
||||
final readonly class HomeAssistantHomeService implements HomeServiceInterface
|
||||
final readonly class HomeAssistantHomeService
|
||||
{
|
||||
public function __construct(
|
||||
private HomeAssistantClient $client,
|
||||
) {
|
||||
}
|
||||
|
||||
public function findEntity(string $entityId): HomeEntityInterface
|
||||
{
|
||||
$entityState = $this->getEntityState($entityId);
|
||||
|
||||
return new HomeAssistantEntity($entityState);
|
||||
}
|
||||
|
||||
public function findAllEntities(): array
|
||||
{
|
||||
$states = $this->getAllEntityStates();
|
||||
|
||||
if (empty($states)) {
|
||||
throw new HomeAssistantException('No entities found');
|
||||
}
|
||||
|
||||
$entities = [];
|
||||
foreach ($states as $state) {
|
||||
$type = HomeEntityType::tryFrom($state->getDomain());
|
||||
|
||||
if ($type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entities[] = new HomeAssistantEntity($state);
|
||||
}
|
||||
|
||||
return array_filter($entities, fn (HomeEntityInterface $entity) => $entity->getType() === HomeEntityType::LIGHT);
|
||||
}
|
||||
|
||||
public function callService(string $service, array $data = []): array
|
||||
{
|
||||
// Extract domain and service name from the service string
|
||||
if (str_contains($service, '.')) {
|
||||
[$domain, $serviceName] = explode('.', $service, 2);
|
||||
|
||||
return $this->client->callService($domain, $serviceName, $data);
|
||||
}
|
||||
|
||||
throw new HomeAssistantException("Invalid service format. Expected 'domain.service'");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityState[]
|
||||
*/
|
||||
@ -81,41 +30,4 @@ final readonly class HomeAssistantHomeService implements HomeServiceInterface
|
||||
|
||||
return EntityState::fromArray($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityState[]
|
||||
*/
|
||||
public function getEntitiesByDomain(string $domain): array
|
||||
{
|
||||
$allStates = $this->getAllEntityStates();
|
||||
|
||||
return array_filter(
|
||||
$allStates,
|
||||
static fn (EntityState $state): bool => $state->getDomain() === $domain,
|
||||
);
|
||||
}
|
||||
|
||||
public function turnOn(string $entityId): EntityState
|
||||
{
|
||||
$this->client->turnOn($entityId);
|
||||
|
||||
return $this->getEntityState($entityId);
|
||||
}
|
||||
|
||||
public function turnOff(string $entityId): EntityState
|
||||
{
|
||||
$this->client->turnOff($entityId);
|
||||
|
||||
return $this->getEntityState($entityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAvailableDomains(): array
|
||||
{
|
||||
$services = $this->client->getServices();
|
||||
|
||||
return array_keys($services);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,27 @@ final class CalendarExportService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array{
|
||||
* date: DateTimeImmutable,
|
||||
* weekday: int,
|
||||
* weekdayName: string,
|
||||
* weekNumber: int,
|
||||
* class: string,
|
||||
* isFtk: bool,
|
||||
* isUrlaub: bool
|
||||
* }> $days
|
||||
* @param array<array{
|
||||
* last_changed: string,
|
||||
* state: string
|
||||
* }> $entityHistory
|
||||
*
|
||||
* @param array<array{
|
||||
* date: DateTimeImmutable,
|
||||
* isFtk: bool,
|
||||
* isUrlaub: bool
|
||||
* }> $absences
|
||||
*/
|
||||
public function generateIcsContent(array $days, array $entityHistory, array $absences): string
|
||||
{
|
||||
$icsContent = [
|
||||
@ -38,21 +59,16 @@ final class CalendarExportService
|
||||
}
|
||||
|
||||
$dayDate = clone $day['date'];
|
||||
$startOfDay = DateTimeImmutable::createFromInterface($dayDate)->setTime(0, 0, 0);
|
||||
$typicalEndOfDay = DateTimeImmutable::createFromInterface($dayDate)->setTime(17, 30, 0);
|
||||
|
||||
$filteredEntityHistory = array_filter($entityHistory, function (array $state) use ($startOfDay, $typicalEndOfDay) {
|
||||
return $state['last_changed'] >= $startOfDay && $state['last_changed'] <= $typicalEndOfDay;
|
||||
$filteredEntityHistory = array_filter($entityHistory, function (array $state) use ($dayDate) {
|
||||
return new DateTimeImmutable($state['last_changed']) >= $dayDate->setTime(0, 0, 0) && new DateTimeImmutable($state['last_changed']) <= $dayDate->setTime(23, 59, 59);
|
||||
});
|
||||
|
||||
$startAndEndTimes = $this->getWorkTimesFromHomeAssistant($filteredEntityHistory, $dayDate);
|
||||
$startAndEndTimes = $this->getWorkTimesFromHomeAssistant($filteredEntityHistory);
|
||||
|
||||
if ($startAndEndTimes === null) {
|
||||
$eventStart = clone $day['date'];
|
||||
$eventStart->setTime(9, 0, 0);
|
||||
|
||||
$eventEnd = clone $day['date'];
|
||||
$eventEnd->setTime(17, 30, 0);
|
||||
if ($startAndEndTimes === null || count($filteredEntityHistory) === 0) {
|
||||
$eventStart = $dayDate->setTime(9, 0, 0);
|
||||
$eventEnd = $dayDate->setTime(18, 0, 0);
|
||||
} else {
|
||||
[$eventStart, $eventEnd] = $startAndEndTimes;
|
||||
}
|
||||
@ -80,17 +96,28 @@ final class CalendarExportService
|
||||
return implode("\r\n", $icsContent);
|
||||
}
|
||||
|
||||
private function getWorkTimesFromHomeAssistant(array $stateHistory, DateTimeInterface $date): ?array
|
||||
/**
|
||||
* @param array<array{
|
||||
* last_changed: string,
|
||||
* state: string
|
||||
* }> $states
|
||||
*
|
||||
* @return array{
|
||||
* start: DateTimeImmutable,
|
||||
* end: DateTimeImmutable
|
||||
* }|null
|
||||
*/
|
||||
private function getWorkTimesFromHomeAssistant(array $states): ?array
|
||||
{
|
||||
try {
|
||||
|
||||
if (empty($stateHistory) || empty($stateHistory[0])) {
|
||||
if (count($states) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$states = array_values($states);
|
||||
|
||||
$startTime = null;
|
||||
$endTime = null;
|
||||
$states = $stateHistory[0];
|
||||
|
||||
foreach ($states as $i => $state) {
|
||||
if ($state['state'] === self::OFFICE_STATE) {
|
||||
|
||||
@ -7,6 +7,7 @@ use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DatePeriod;
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use IntlDateFormatter;
|
||||
|
||||
final class CalendarService
|
||||
@ -25,6 +26,19 @@ final class CalendarService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $startDate
|
||||
* @param string $endDate
|
||||
* @return array<array{
|
||||
* date: DateTimeImmutable,
|
||||
* weekday: int,
|
||||
* weekdayName: string,
|
||||
* weekNumber: int,
|
||||
* class: string,
|
||||
* isFtk: bool,
|
||||
* isUrlaub: bool
|
||||
* }>
|
||||
*/
|
||||
public function getAllDays(string $startDate, string $endDate): array
|
||||
{
|
||||
$period = new DatePeriod(
|
||||
@ -37,7 +51,7 @@ final class CalendarService
|
||||
foreach ($period as $date) {
|
||||
$dateObj = DateTimeImmutable::createFromInterface($date);
|
||||
$days[] = [
|
||||
'date' => $date,
|
||||
'date' => $dateObj,
|
||||
'weekday' => (int) $dateObj->format('N'),
|
||||
'weekdayName' => $this->formatter->format($date),
|
||||
'weekNumber' => (int) $dateObj->format('W'),
|
||||
@ -95,7 +109,7 @@ final class CalendarService
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isSameDay(DateTime $date1, DateTime $date2): bool
|
||||
private function isSameDay(DateTimeInterface $date1, DateTimeInterface $date2): bool
|
||||
{
|
||||
return $date1->format('Y-m-d') === $date2->format('Y-m-d');
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user