2023-10-13 21:33:13 +00:00
|
|
|
import 'dart:async';
|
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
|
|
|
|
import '../constants.dart';
|
2023-10-14 06:41:27 +00:00
|
|
|
import '../states/plug_settings.dart';
|
2023-10-13 21:33:13 +00:00
|
|
|
import 'devices.dart';
|
|
|
|
|
|
|
|
class Plug extends Device {
|
2023-10-19 14:26:09 +00:00
|
|
|
|
|
|
|
Plug(this.device_id, this.device_descriptor, this.led_state, this.power_state,
|
|
|
|
this.power_draw, this.power_control);
|
2023-10-13 21:33:13 +00:00
|
|
|
final String device_id;
|
|
|
|
String? device_descriptor;
|
|
|
|
bool led_state;
|
|
|
|
bool power_state;
|
|
|
|
double power_draw;
|
|
|
|
bool power_control;
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
static Future<Plug> create(Map<String, dynamic> deviceInfo) async {
|
|
|
|
final String deviceId = deviceInfo['id'];
|
|
|
|
final String? deviceDescriptor = deviceInfo['desc'];
|
|
|
|
final bool powerControl = deviceInfo['toggle'];
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
final response = await http
|
2023-10-19 14:26:09 +00:00
|
|
|
.get(Uri.parse("${Constants.BASE_URL}/plug_state/$deviceId"));
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
if (response.statusCode != 200) {
|
2023-10-19 14:26:09 +00:00
|
|
|
throw Exception("Failed to fetch plug_state for $deviceId");
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
final Map<String, dynamic> deviceState =
|
2023-10-13 21:33:13 +00:00
|
|
|
Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
|
|
|
|
|
|
|
return Plug(
|
2023-10-19 14:26:09 +00:00
|
|
|
deviceId,
|
|
|
|
deviceDescriptor,
|
|
|
|
deviceState["led"],
|
|
|
|
deviceState["power"],
|
|
|
|
deviceState["power_draw"],
|
|
|
|
powerControl && deviceState["power_draw"] < 15,
|
2023-10-13 21:33:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2023-10-14 06:41:27 +00:00
|
|
|
Widget create_widget(BuildContext context) {
|
2023-10-19 14:26:09 +00:00
|
|
|
const double headerHeight = 40;
|
|
|
|
const double infoHeight = 30;
|
|
|
|
const double infoWidth = 60;
|
|
|
|
const double xOffset = 0.9;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
return Table(
|
2023-10-14 09:33:49 +00:00
|
|
|
border: TableBorder(
|
|
|
|
borderRadius: BorderRadius.circular(Constants.TABLE_RADIUS)),
|
2023-10-13 21:33:13 +00:00
|
|
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
|
|
|
columnWidths: const {
|
|
|
|
0: FixedColumnWidth(200.0),
|
|
|
|
1: FixedColumnWidth(200.0),
|
|
|
|
},
|
|
|
|
children: [
|
|
|
|
TableRow(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
color: Colors.deepPurple[200],
|
2023-10-14 09:33:49 +00:00
|
|
|
borderRadius: BorderRadius.circular(Constants.TABLE_RADIUS),
|
2023-10-13 21:33:13 +00:00
|
|
|
),
|
|
|
|
children: [
|
|
|
|
SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
height: headerHeight,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
Align(
|
|
|
|
child: Text(
|
|
|
|
style: const TextStyle(
|
|
|
|
fontWeight: FontWeight.bold),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
device_descriptor ?? device_id)),
|
|
|
|
Align(
|
|
|
|
alignment: Alignment.centerRight,
|
|
|
|
child: IconButton(
|
2023-10-14 06:41:27 +00:00
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context).pushReplacementNamed(
|
|
|
|
'/plug_settings',
|
|
|
|
arguments: PlugSettingsArguments(
|
2023-10-14 09:33:49 +00:00
|
|
|
device_id, device_descriptor));
|
2023-10-14 06:41:27 +00:00
|
|
|
},
|
2023-10-13 21:33:13 +00:00
|
|
|
icon: const Icon(Icons.settings)),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
))
|
|
|
|
]),
|
|
|
|
TableRow(children: [
|
|
|
|
SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
height: infoHeight,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: Stack(children: [
|
|
|
|
const Align(
|
|
|
|
alignment: Alignment(-0.9, 0.0),
|
|
|
|
child: Text(
|
|
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
"LED")),
|
|
|
|
Align(
|
2023-10-19 14:26:09 +00:00
|
|
|
alignment: const Alignment(xOffset, 0.0),
|
2023-10-13 21:33:13 +00:00
|
|
|
child: SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
width: infoWidth,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: PlugLed(
|
|
|
|
device_id: device_id, led_state: led_state))),
|
|
|
|
]))
|
|
|
|
]),
|
|
|
|
TableRow(children: [
|
|
|
|
SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
height: infoHeight,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: Stack(children: [
|
|
|
|
const Align(
|
|
|
|
alignment: Alignment(-0.9, 0.0),
|
|
|
|
child: Text(
|
|
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
"Power")),
|
|
|
|
Align(
|
2023-10-19 14:26:09 +00:00
|
|
|
alignment: const Alignment(xOffset, 0.0),
|
2023-10-13 21:33:13 +00:00
|
|
|
child: SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
width: infoWidth,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: PlugPower(
|
|
|
|
device_id: device_id,
|
|
|
|
power_state: power_state,
|
|
|
|
power_control: power_control))),
|
|
|
|
]))
|
|
|
|
]),
|
|
|
|
TableRow(children: [
|
|
|
|
SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
height: infoHeight,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: Stack(children: [
|
|
|
|
const Align(
|
|
|
|
alignment: Alignment(-0.9, 0.0),
|
|
|
|
child: Text(
|
|
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
"Power Draw")),
|
|
|
|
Align(
|
2023-10-19 14:26:09 +00:00
|
|
|
alignment: const Alignment(xOffset, 0.0),
|
2023-10-13 21:33:13 +00:00
|
|
|
child: SizedBox(
|
2023-10-19 14:26:09 +00:00
|
|
|
width: infoWidth,
|
2023-10-13 21:33:13 +00:00
|
|
|
child: Text(
|
|
|
|
textAlign: TextAlign.center, "$power_draw W")))
|
|
|
|
]))
|
|
|
|
])
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class PlugLed extends StatefulWidget {
|
|
|
|
|
|
|
|
PlugLed({super.key, required this.device_id, required this.led_state});
|
2023-10-19 14:26:09 +00:00
|
|
|
final String device_id;
|
|
|
|
bool led_state;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
@override
|
2023-10-14 06:41:27 +00:00
|
|
|
State<PlugLed> createState() => PlugLedState();
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class PlugLedState extends State<PlugLed> {
|
2023-10-14 06:41:27 +00:00
|
|
|
String _led_state_info = "";
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
void _toggle_led_state() {
|
2023-10-19 14:26:09 +00:00
|
|
|
String targetState;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
2023-10-14 06:41:27 +00:00
|
|
|
if (widget.led_state) {
|
2023-10-19 14:26:09 +00:00
|
|
|
targetState = "off";
|
2023-10-13 21:33:13 +00:00
|
|
|
} else {
|
2023-10-19 14:26:09 +00:00
|
|
|
targetState = "on";
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
change_plug_state(widget.device_id, "led", targetState)
|
|
|
|
.then((deviceState) {
|
|
|
|
widget.led_state = deviceState["led"];
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
setState(() {
|
2023-10-14 06:41:27 +00:00
|
|
|
_led_state_info = widget.led_state ? "On" : "Off";
|
2023-10-13 21:33:13 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2023-10-14 06:41:27 +00:00
|
|
|
_led_state_info = widget.led_state ? "On" : "Off";
|
|
|
|
|
2023-10-13 21:33:13 +00:00
|
|
|
return TextButton(
|
|
|
|
onPressed: _toggle_led_state,
|
|
|
|
child: Text(textAlign: TextAlign.center, _led_state_info));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class PlugPower extends StatefulWidget {
|
|
|
|
|
|
|
|
PlugPower(
|
|
|
|
{super.key,
|
|
|
|
required this.device_id,
|
|
|
|
required this.power_state,
|
|
|
|
required this.power_control});
|
2023-10-19 14:26:09 +00:00
|
|
|
final String device_id;
|
|
|
|
bool power_state;
|
|
|
|
bool power_control;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
@override
|
2023-10-14 06:41:27 +00:00
|
|
|
State<PlugPower> createState() => PlugPowerState();
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class PlugPowerState extends State<PlugPower> {
|
2023-10-14 06:41:27 +00:00
|
|
|
String _power_state_info = "";
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
void _toggle_power_state() {
|
2023-10-19 14:26:09 +00:00
|
|
|
String targetState;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
2023-10-14 06:41:27 +00:00
|
|
|
if (widget.power_state) {
|
2023-10-19 14:26:09 +00:00
|
|
|
targetState = "off";
|
2023-10-13 21:33:13 +00:00
|
|
|
} else {
|
2023-10-19 14:26:09 +00:00
|
|
|
targetState = "on";
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
change_plug_state(widget.device_id, "power", targetState)
|
|
|
|
.then((deviceState) {
|
|
|
|
widget.power_state = deviceState["power"];
|
2023-10-13 21:33:13 +00:00
|
|
|
|
2023-10-19 14:26:09 +00:00
|
|
|
widget.power_control = deviceState["power_draw"] < 15;
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
setState(() {
|
2023-10-14 06:41:27 +00:00
|
|
|
_power_state_info = widget.power_state ? "On" : "Off";
|
2023-10-13 21:33:13 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2023-10-14 06:41:27 +00:00
|
|
|
_power_state_info = widget.power_state ? "On" : "Off";
|
|
|
|
|
|
|
|
if (widget.power_control) {
|
2023-10-13 21:33:13 +00:00
|
|
|
return TextButton(
|
|
|
|
onPressed: _toggle_power_state,
|
|
|
|
child: Text(textAlign: TextAlign.center, _power_state_info));
|
|
|
|
} else {
|
|
|
|
return Text(_power_state_info, textAlign: TextAlign.center);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Map<String, dynamic>> change_plug_state(
|
2023-10-19 14:26:09 +00:00
|
|
|
String deviceId, String module, String state) async {
|
2023-10-13 21:33:13 +00:00
|
|
|
var response = await http.post(
|
2023-10-19 14:26:09 +00:00
|
|
|
Uri.parse("${Constants.BASE_URL}/plug/$deviceId/${module}_$state"));
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
if (response.statusCode != 200) {
|
|
|
|
throw Exception("Failed to post new state");
|
|
|
|
}
|
|
|
|
|
|
|
|
response =
|
2023-10-19 14:26:09 +00:00
|
|
|
await http.get(Uri.parse("${Constants.BASE_URL}/plug_state/$deviceId"));
|
2023-10-13 21:33:13 +00:00
|
|
|
|
|
|
|
if (response.statusCode != 200) {
|
2023-10-19 14:26:09 +00:00
|
|
|
throw Exception("Failed to fetch plug_state for $deviceId");
|
2023-10-13 21:33:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
|
|
|
}
|