feat: ignis app v1.0.0 -- управление WiZ лампами
This commit is contained in:
85
lib/services/api_client.dart
Normal file
85
lib/services/api_client.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
/// HTTP-клиент для одного сервера Ignis.
|
||||
/// Покрывает все эндпоинты из openapi.json.
|
||||
class IgnisApi {
|
||||
final Dio _dio = Dio();
|
||||
Dio get dioInstance => _dio;
|
||||
|
||||
/// Инициализация базового URL и API-ключа
|
||||
void init(String baseUrl, String apiKey) {
|
||||
String url = baseUrl.trim();
|
||||
if (!url.startsWith('http')) {
|
||||
url = 'https://$url';
|
||||
}
|
||||
// Убираем trailing slash
|
||||
if (url.endsWith('/')) url = url.substring(0, url.length - 1);
|
||||
|
||||
_dio.options.baseUrl = url;
|
||||
_dio.options.headers['X-API-Key'] = apiKey;
|
||||
// Бэкенд WiZ ламп тормозит -- даём запас
|
||||
_dio.options.connectTimeout = const Duration(seconds: 15);
|
||||
_dio.options.receiveTimeout = const Duration(seconds: 15);
|
||||
}
|
||||
|
||||
// ─── Устройства и группы ───────────────────────────────────
|
||||
|
||||
/// Все устройства (лампы)
|
||||
Future<Response> getDevices() => _dio.get('/devices');
|
||||
|
||||
/// Все группы
|
||||
Future<Response> getGroups() => _dio.get('/devices/groups');
|
||||
|
||||
/// Все доступные сцены
|
||||
Future<Response> getScenes() => _dio.get('/devices/scenes');
|
||||
|
||||
/// Создать группу
|
||||
Future<Response> createGroup(String id, String name, List<String> macs) =>
|
||||
_dio.post('/devices/groups', data: {'id': id, 'name': name, 'macs': macs});
|
||||
|
||||
/// Удалить группу
|
||||
Future<Response> deleteGroup(String groupId) =>
|
||||
_dio.delete('/devices/groups/$groupId');
|
||||
|
||||
/// Пересканировать сеть (найти новые лампы)
|
||||
Future<Response> rescanNetwork() => _dio.post('/devices/rescan');
|
||||
|
||||
// ─── Управление ────────────────────────────────────────────
|
||||
|
||||
/// Управление группой: state, brightness, temp, scene, r/g/b
|
||||
Future<Response> controlGroup(String id, Map<String, dynamic> params) =>
|
||||
_dio.post('/control/group/$id', queryParameters: params);
|
||||
|
||||
/// Управление одной лампой
|
||||
Future<Response> controlDevice(String id, Map<String, dynamic> params) =>
|
||||
_dio.post('/control/device/$id', queryParameters: params);
|
||||
|
||||
/// Мигнуть лампой (для идентификации)
|
||||
Future<Response> blinkDevice(String id) =>
|
||||
_dio.post('/control/device/$id/blink');
|
||||
|
||||
/// Статус группы (реальный опрос ламп)
|
||||
Future<Response> getGroupStatus(String id) =>
|
||||
_dio.get('/control/group/$id/status');
|
||||
|
||||
/// Статус одной лампы
|
||||
Future<Response> getDeviceStatus(String id) =>
|
||||
_dio.get('/control/device/$id/status');
|
||||
|
||||
// ─── Расписания ────────────────────────────────────────────
|
||||
|
||||
/// Одноразовое расписание (таймер)
|
||||
Future<Response> scheduleOnce(Map<String, dynamic> params) =>
|
||||
_dio.post('/schedules/once', queryParameters: params);
|
||||
|
||||
/// Cron-расписание (повторяющееся)
|
||||
Future<Response> scheduleCron(Map<String, dynamic> params) =>
|
||||
_dio.post('/schedules/cron', queryParameters: params);
|
||||
|
||||
/// Все активные задачи расписания
|
||||
Future<Response> getTasks() => _dio.get('/schedules/tasks');
|
||||
|
||||
/// Отменить задачу расписания
|
||||
Future<Response> cancelTask(String jobId) =>
|
||||
_dio.delete('/schedules/$jobId');
|
||||
}
|
||||
78
lib/services/settings_service.dart
Normal file
78
lib/services/settings_service.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'dart:convert';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../models/home_config.dart';
|
||||
|
||||
/// Сервис для хранения списка "домов" и текущего выбранного.
|
||||
/// Данные лежат в SharedPreferences как JSON-массив.
|
||||
class SettingsService {
|
||||
static const String _homesKey = 'ignis_homes';
|
||||
static const String _currentHomeKey = 'ignis_current_home_id';
|
||||
|
||||
/// Загрузить все дома
|
||||
Future<List<HomeConfig>> getHomes() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final raw = prefs.getString(_homesKey);
|
||||
if (raw == null || raw.isEmpty) return [];
|
||||
final list = jsonDecode(raw) as List<dynamic>;
|
||||
return list.map((e) => HomeConfig.fromJson(e as Map<String, dynamic>)).toList();
|
||||
}
|
||||
|
||||
/// Сохранить весь список домов
|
||||
Future<void> saveHomes(List<HomeConfig> homes) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_homesKey, jsonEncode(homes.map((h) => h.toJson()).toList()));
|
||||
}
|
||||
|
||||
/// Добавить или обновить дом
|
||||
Future<void> upsertHome(HomeConfig home) async {
|
||||
final homes = await getHomes();
|
||||
final idx = homes.indexWhere((h) => h.id == home.id);
|
||||
if (idx >= 0) {
|
||||
homes[idx] = home;
|
||||
} else {
|
||||
homes.add(home);
|
||||
}
|
||||
await saveHomes(homes);
|
||||
}
|
||||
|
||||
/// Удалить дом по id
|
||||
Future<void> deleteHome(String id) async {
|
||||
final homes = await getHomes();
|
||||
homes.removeWhere((h) => h.id == id);
|
||||
await saveHomes(homes);
|
||||
|
||||
// Если удалили текущий -- сбрасываем выбор
|
||||
final currentId = await getCurrentHomeId();
|
||||
if (currentId == id) {
|
||||
await setCurrentHomeId(homes.isNotEmpty ? homes.first.id : null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Получить id текущего активного дома
|
||||
Future<String?> getCurrentHomeId() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(_currentHomeKey);
|
||||
}
|
||||
|
||||
/// Установить текущий дом
|
||||
Future<void> setCurrentHomeId(String? id) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (id == null) {
|
||||
await prefs.remove(_currentHomeKey);
|
||||
} else {
|
||||
await prefs.setString(_currentHomeKey, id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Удобный метод: получить текущий HomeConfig или null
|
||||
Future<HomeConfig?> getCurrentHome() async {
|
||||
final homes = await getHomes();
|
||||
final id = await getCurrentHomeId();
|
||||
if (id == null && homes.isNotEmpty) return homes.first;
|
||||
try {
|
||||
return homes.firstWhere((h) => h.id == id);
|
||||
} catch (_) {
|
||||
return homes.isNotEmpty ? homes.first : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user