106 lines
3.0 KiB
Dart
106 lines
3.0 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:mirror_core/mirror_core.dart';
|
|
import 'settings_provider.dart';
|
|
|
|
final haServiceProvider = Provider<HomeAssistantService?>((ref) {
|
|
final settings = ref.watch(settingsProvider).valueOrNull;
|
|
if (settings == null || settings.haBaseUrl == null || settings.haToken == null) {
|
|
return null;
|
|
}
|
|
return HomeAssistantService(
|
|
baseUrl: settings.haBaseUrl!,
|
|
token: settings.haToken!,
|
|
);
|
|
});
|
|
|
|
final haEntitiesProvider =
|
|
AsyncNotifierProvider<HaEntitiesNotifier, HaEntitiesState>(HaEntitiesNotifier.new);
|
|
|
|
class HaEntitiesState {
|
|
final List<HaEntity> entities;
|
|
final HaWeather? weather;
|
|
final List<HaCalendarEvent> calendarEvents;
|
|
final String? error;
|
|
|
|
const HaEntitiesState({
|
|
this.entities = const [],
|
|
this.weather,
|
|
this.calendarEvents = const [],
|
|
this.error,
|
|
});
|
|
}
|
|
|
|
class HaEntitiesNotifier extends AsyncNotifier<HaEntitiesState> {
|
|
@override
|
|
Future<HaEntitiesState> build() async {
|
|
final service = ref.watch(haServiceProvider);
|
|
if (service == null) {
|
|
return const HaEntitiesState(error: 'Configure Home Assistant in Settings');
|
|
}
|
|
try {
|
|
final entities = await service.getStates();
|
|
// Find weather entity
|
|
final weatherEntity = entities.firstWhere(
|
|
(e) => e.entityId.startsWith('weather.'),
|
|
orElse: () => HaEntity(entityId: '', state: '', attributes: {}, lastChanged: null),
|
|
);
|
|
HaWeather? weather;
|
|
if (weatherEntity.entityId.isNotEmpty) {
|
|
weather = HaWeather.fromEntity(weatherEntity);
|
|
}
|
|
return HaEntitiesState(
|
|
entities: entities,
|
|
weather: weather,
|
|
);
|
|
} catch (e) {
|
|
return HaEntitiesState(error: 'HA connection failed: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> toggleEntity(String entityId) async {
|
|
final service = ref.read(haServiceProvider);
|
|
if (service == null) return;
|
|
|
|
final entity = state.valueOrNull?.entities.firstWhere(
|
|
(e) => e.entityId == entityId,
|
|
orElse: () => HaEntity(entityId: '', state: '', attributes: {}, lastChanged: null),
|
|
);
|
|
if (entity == null || entity.entityId.isEmpty) return;
|
|
|
|
final isOn = entity.state == 'on';
|
|
if (isOn) {
|
|
await service.turnOff(entityId);
|
|
} else {
|
|
await service.turnOn(entityId);
|
|
}
|
|
// Refresh state
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
Future<void> callScene(String entityId) async {
|
|
final service = ref.read(haServiceProvider);
|
|
if (service == null) return;
|
|
await service.callService('scene', 'turn_on', entityId: entityId);
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
void refresh() => ref.invalidateSelf();
|
|
}
|
|
|
|
class HaWeather {
|
|
final double? temperature;
|
|
final String? condition;
|
|
final double? humidity;
|
|
|
|
const HaWeather({this.temperature, this.condition, this.humidity});
|
|
|
|
factory HaWeather.fromEntity(HaEntity entity) {
|
|
final attrs = entity.attributes;
|
|
return HaWeather(
|
|
temperature: (attrs['temperature'] as num?)?.toDouble(),
|
|
condition: entity.state,
|
|
humidity: (attrs['humidity'] as num?)?.toDouble(),
|
|
);
|
|
}
|
|
}
|