Compare commits

...

4 Commits

3 changed files with 123 additions and 12 deletions

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
@@ -44,6 +46,16 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
}
// 25.12.03 지은 추가 끝
Future<Map<String, dynamic>?> test() async {
final data = await _api.getTimeseries(target: "*", limit: 200);
if (data != null) {
print("받은 데이터 길이: ${data['samples'].length}");
print(data['samples'][0]); // 첫 번째 데이터 출력
}
return data;
}
int _selectedImageIndex = 0;
static const BoxShadow _cleanShadow = BoxShadow(
@@ -60,6 +72,46 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
'FAN': false,
};
double? _battPct;
double? _volt;
double? _temp;
double? _humi;
Timer? _timer;
@override
void initState() {
super.initState();
_loadBattPct();
_timer = Timer.periodic(const Duration(seconds: 2), (_) => _loadBattPct());
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
Future<void> _loadBattPct() async {
final data = await test(); // Future → Map으로 resolve
if (data == null) return;
// samples[0]에서 batt_pct 값 읽기
final battPct = data['samples'][0]['batt_pct'];
final volt = data['samples'][0]['pv_volt'];
final temp = data['samples'][0]['temp'];
final humi = data['samples'][0]['humi'];
setState(() {
// 숫자/문자 둘 다 안전하게 처리
_battPct = battPct.toDouble();
_volt = volt.toDouble();
_temp = temp.toDouble();
_humi = humi.toDouble();
});
}
@override
Widget build(BuildContext context) {
return Container(
@@ -273,11 +325,20 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
painter: _BatteryArcPainter(
backgroundColor: _accentContainerColor,
color: _mainBlueColor,
percentage: 1.0,
percentage: _battPct!.floor()/100 ,
),
),
),
Text('86', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: _mainTextColor)),
Text(
_battPct == null
? '--' // 아직 로딩 전
: _battPct!.floor().toString(),
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: _mainTextColor,
),
),
],
),
),
@@ -503,9 +564,21 @@ class _HomeScreenContentState extends State<HomeScreenContent> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSensorInfoRow(Icons.water_drop_outlined, '습도: 60%', '습도'),
_buildSensorInfoRow(
Icons.water_drop_outlined,
_humi == null
? '--' // 아직 로딩 전
: '습도: '+_humi!.floor().toString()+'%',
'습도'
),
const SizedBox(height: 24),
_buildSensorInfoRow(Icons.thermostat, '온도: 24.5℃', '온도'),
_buildSensorInfoRow(
Icons.thermostat,
_temp == null
? '--' // 아직 로딩 전
: '온도: '+_temp!.floor().toString()+'',
'온도'
),
],
),
),

View File

@@ -40,6 +40,37 @@ class LockerApi {
}
}
Future<Map<String, dynamic>?> getTimeseries({
String target = "*",
int limit = 200,
}) async {
final url = Uri.parse('$baseUrl/timeseries/get');
try {
final response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: jsonEncode({
"target": target,
"limit": limit,
}),
);
if (response.statusCode == 200) {
final jsonData = jsonDecode(response.body);
print("Timeseries 수신 성공");
return jsonData;
} else {
print("Timeseries 조회 실패: ${response.body}");
return null;
}
} catch (e) {
print("서버 연결 오류: $e");
return null;
}
}
// --- [기능별 동작 함수] ---
// 1. 잠금 해제 (주소: 0x0016 / 값: 1)

View File

@@ -166,13 +166,20 @@ const String _locationTermContent =
'부칙 제1조 (시행일)\n'
'본 약관은 2025년 11월 28일부터 시행합니다.\n';
const String _marketingTermContent = """
1. 수집 및 이용 목적
이벤트 정보 및 참여 기회 제공, 광고성 정보 제공 등 마케팅 활동을 위해 사용됩니다.
2. 수신 동의 철회
회원은 언제든지 설정 메뉴 또는 고객센터를 통해 마케팅 정보 수신 동의를 철회할 수 있습니다. 수신 동의를 철회하더라도 기본 서비스 이용에는 제한이 없습니다.
""";
const String _marketingTermContent =
'(주)메타큐랩이 제공하는 이벤트 및 혜택 등 마케팅 정보를 수신하는 것에 동의합니다.\n\n'
'1. 수집 및 이용 목적\n'
'- 신규 서비스(기능) 개발 및 맞춤 서비스 제공.\n'
'- 이벤트, 프로모션, 혜택 등 광고성 정보 제공.\n'
'- 서비스 이용 통계 및 설문조사.\n\n'
'2. 수집하는 개인정보 항목\n'
'- 이름, 휴대전화번호, 이메일, PUSH 토큰.\n\n'
'3. 보유 및 이용 기간\n'
'- 회원 탈퇴 또는 동의 철회 시까지\n\n'
'4. 전송 방법\n'
'- 앱 푸시(App Push) 알림, SMS(문자메시지), 이메일 등.\n\n'
'5. 동의 거부 권리\n'
'귀하는 마케팅 정보 수신에 대한 동의를 거부할 수 있습니다. 동의를 거부하더라도 회원 가입 및 기본 서비스 이용에는 제한이 없습니다. 다만, 이벤트 및 혜택 정보 제공이 제한될 수 있습니다.\n';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});