Split separate devices
This commit is contained in:
parent
65b9990394
commit
ada210206f
8 changed files with 459 additions and 308 deletions
|
@ -1,307 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
import 'constants.dart';
|
|
||||||
|
|
||||||
class Category {
|
|
||||||
Category(this.name) : devices = [];
|
|
||||||
|
|
||||||
final String name;
|
|
||||||
List<Device> devices;
|
|
||||||
|
|
||||||
static Future<List<Category>> fetch() async {
|
|
||||||
final response = await http.get(Uri.parse("${Constants.BASE_URL}/devices"));
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
throw Exception("Failed to fetch devices");
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Category> categories = [];
|
|
||||||
|
|
||||||
final Map<String, List<dynamic>> json =
|
|
||||||
Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
|
||||||
|
|
||||||
for (MapEntry<String, List<dynamic>> category_entry in json.entries) {
|
|
||||||
final Category category = Category(category_entry.key);
|
|
||||||
|
|
||||||
for (dynamic device_info_dyn in category_entry.value) {
|
|
||||||
final Map<String, dynamic> device_info = device_info_dyn;
|
|
||||||
|
|
||||||
final String device_id = device_info['id'];
|
|
||||||
final String? device_descriptor = device_info['desc'];
|
|
||||||
final bool power_control = device_info['toggle'];
|
|
||||||
|
|
||||||
final response = await http
|
|
||||||
.get(Uri.parse("${Constants.BASE_URL}/plug_state/$device_id"));
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
throw Exception("Failed to fetch plug_state for $device_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, dynamic> device_state =
|
|
||||||
Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
|
||||||
|
|
||||||
final Device device = Device(
|
|
||||||
device_id,
|
|
||||||
device_descriptor,
|
|
||||||
device_state["led"],
|
|
||||||
device_state["power"],
|
|
||||||
device_state["power_draw"],
|
|
||||||
power_control && device_state["power_draw"] < 15,
|
|
||||||
);
|
|
||||||
|
|
||||||
category.devices.add(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
categories.add(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CategoryWidget extends StatelessWidget {
|
|
||||||
final Category category;
|
|
||||||
|
|
||||||
CategoryWidget({super.key, required this.category});
|
|
||||||
|
|
||||||
String Name() {
|
|
||||||
return category.name
|
|
||||||
.split('_')
|
|
||||||
.map((s) => "${s[0].toUpperCase()}${s.substring(1)}")
|
|
||||||
.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
const double header_height = 40;
|
|
||||||
const double info_height = 30;
|
|
||||||
const double x_offset = 0.6;
|
|
||||||
|
|
||||||
return Wrap(
|
|
||||||
spacing: 25,
|
|
||||||
runSpacing: 25,
|
|
||||||
children: category.devices.map((device) {
|
|
||||||
return Table(
|
|
||||||
border: TableBorder.all(),
|
|
||||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
|
||||||
columnWidths: const {
|
|
||||||
0: FixedColumnWidth(200.0),
|
|
||||||
1: FixedColumnWidth(200.0),
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
TableRow(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.deepPurple[200],
|
|
||||||
),
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: header_height,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Align(
|
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
device.device_descriptor ??
|
|
||||||
device.device_id)),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () {},
|
|
||||||
icon: const Icon(Icons.settings)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
))
|
|
||||||
]),
|
|
||||||
TableRow(children: [
|
|
||||||
SizedBox(
|
|
||||||
height: info_height,
|
|
||||||
child: Stack(children: [
|
|
||||||
const Align(
|
|
||||||
alignment: Alignment(-0.9, 0.0),
|
|
||||||
child: Text(
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
"LED")),
|
|
||||||
Align(
|
|
||||||
alignment: const Alignment(x_offset + 0.025, 0.0),
|
|
||||||
child: DeviceLed(
|
|
||||||
device_id: device.device_id,
|
|
||||||
led_state: device.led_state)),
|
|
||||||
]))
|
|
||||||
]),
|
|
||||||
TableRow(children: [
|
|
||||||
SizedBox(
|
|
||||||
height: info_height,
|
|
||||||
child: Stack(children: [
|
|
||||||
const Align(
|
|
||||||
alignment: Alignment(-0.9, 0.0),
|
|
||||||
child: Text(
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
"Power")),
|
|
||||||
Align(
|
|
||||||
alignment: const Alignment(x_offset - 0.1, 0.0),
|
|
||||||
child: DevicePower(
|
|
||||||
device_id: device.device_id,
|
|
||||||
power_state: device.power_state,
|
|
||||||
power_control: device.power_control)),
|
|
||||||
]))
|
|
||||||
]),
|
|
||||||
TableRow(children: [
|
|
||||||
SizedBox(
|
|
||||||
height: info_height,
|
|
||||||
child: Stack(children: [
|
|
||||||
const Align(
|
|
||||||
alignment: Alignment(-0.9, 0.0),
|
|
||||||
child: Text(
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
"Power Draw")),
|
|
||||||
Align(
|
|
||||||
alignment: const Alignment(x_offset, 0.0),
|
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
"${device.power_draw} W"))
|
|
||||||
]))
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Device {
|
|
||||||
final String device_id;
|
|
||||||
String? device_descriptor;
|
|
||||||
bool led_state;
|
|
||||||
bool power_state;
|
|
||||||
double power_draw;
|
|
||||||
bool power_control;
|
|
||||||
|
|
||||||
Device(this.device_id, this.device_descriptor, this.led_state,
|
|
||||||
this.power_state, this.power_draw, this.power_control);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeviceLed extends StatefulWidget {
|
|
||||||
final String device_id;
|
|
||||||
final bool led_state;
|
|
||||||
|
|
||||||
DeviceLed({super.key, required this.device_id, required this.led_state});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DeviceLed> createState() => DeviceLedState(device_id, led_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeviceLedState extends State<DeviceLed> {
|
|
||||||
final String device_id;
|
|
||||||
bool led_state;
|
|
||||||
String _led_state_info;
|
|
||||||
|
|
||||||
DeviceLedState(this.device_id, this.led_state)
|
|
||||||
: this._led_state_info = led_state ? "On" : "Off";
|
|
||||||
|
|
||||||
void _toggle_led_state() {
|
|
||||||
String target_state;
|
|
||||||
|
|
||||||
if (led_state) {
|
|
||||||
target_state = "off";
|
|
||||||
} else {
|
|
||||||
target_state = "on";
|
|
||||||
}
|
|
||||||
|
|
||||||
change_plug_state(device_id, "led", target_state).then((device_state) {
|
|
||||||
led_state = device_state["led"];
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_led_state_info = led_state ? "On" : "Off";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return TextButton(
|
|
||||||
onPressed: _toggle_led_state,
|
|
||||||
child: Text(textAlign: TextAlign.center, _led_state_info));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DevicePower extends StatefulWidget {
|
|
||||||
final String device_id;
|
|
||||||
final bool power_state;
|
|
||||||
final bool power_control;
|
|
||||||
|
|
||||||
DevicePower(
|
|
||||||
{super.key,
|
|
||||||
required this.device_id,
|
|
||||||
required this.power_state,
|
|
||||||
required this.power_control});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DevicePower> createState() =>
|
|
||||||
DevicePowerState(device_id, power_state, power_control);
|
|
||||||
}
|
|
||||||
|
|
||||||
class DevicePowerState extends State<DevicePower> {
|
|
||||||
final String device_id;
|
|
||||||
bool power_state;
|
|
||||||
String _power_state_info;
|
|
||||||
bool power_control;
|
|
||||||
|
|
||||||
DevicePowerState(this.device_id, this.power_state, this.power_control)
|
|
||||||
: this._power_state_info = power_state ? "On" : "Off";
|
|
||||||
|
|
||||||
void _toggle_power_state() {
|
|
||||||
String target_state;
|
|
||||||
|
|
||||||
if (power_state) {
|
|
||||||
target_state = "off";
|
|
||||||
} else {
|
|
||||||
target_state = "on";
|
|
||||||
}
|
|
||||||
|
|
||||||
change_plug_state(device_id, "power", target_state).then((device_state) {
|
|
||||||
power_state = device_state["power"];
|
|
||||||
|
|
||||||
power_control = device_state["power_draw"] < 15;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_power_state_info = power_state ? "On" : "Off";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (power_control) {
|
|
||||||
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(
|
|
||||||
String device_id, String module, String state) async {
|
|
||||||
var response = await http.post(
|
|
||||||
Uri.parse("${Constants.BASE_URL}/plug/$device_id/${module}_$state"));
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
throw Exception("Failed to post new state");
|
|
||||||
}
|
|
||||||
|
|
||||||
response =
|
|
||||||
await http.get(Uri.parse("${Constants.BASE_URL}/plug_state/$device_id"));
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
throw Exception("Failed to fetch plug_state for $device_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
|
||||||
}
|
|
133
frontend/lib/devices/devices.dart
Normal file
133
frontend/lib/devices/devices.dart
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../constants.dart';
|
||||||
|
|
||||||
|
import 'dish_washer.dart';
|
||||||
|
import 'plug.dart';
|
||||||
|
import 'temp_humid.dart';
|
||||||
|
import 'thermostat.dart';
|
||||||
|
import 'washing_machine.dart';
|
||||||
|
|
||||||
|
class Category {
|
||||||
|
Category(this.name) : devices = [];
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
List<Device> devices;
|
||||||
|
|
||||||
|
static Future<List<Category>> fetch() async {
|
||||||
|
final response = await http.get(Uri.parse("${Constants.BASE_URL}/devices"));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception("Failed to fetch devices");
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Category> categories = [];
|
||||||
|
|
||||||
|
final Map<String, List<dynamic>> json =
|
||||||
|
Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
||||||
|
|
||||||
|
// create plugs
|
||||||
|
{
|
||||||
|
final Category category = Category('plugs');
|
||||||
|
final List<dynamic> plugs = json['plugs']!;
|
||||||
|
|
||||||
|
for (dynamic device_info_dyn in plugs) {
|
||||||
|
final Map<String, dynamic> device_info = device_info_dyn;
|
||||||
|
|
||||||
|
category.devices.add(await Plug.create(device_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.add(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create thermostat
|
||||||
|
{
|
||||||
|
final Category category = Category('thermostat');
|
||||||
|
final List<dynamic> thermostats = json['thermostat']!;
|
||||||
|
|
||||||
|
for (dynamic device_info_dyn in thermostats) {
|
||||||
|
final Map<String, dynamic> device_info = device_info_dyn;
|
||||||
|
|
||||||
|
category.devices.add(await Thermostat.create(device_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.add(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create temperature_and_humidity
|
||||||
|
{
|
||||||
|
final Category category = Category('temperature_and_humidity');
|
||||||
|
final List<dynamic> temperature_and_humidities =
|
||||||
|
json['temperature_and_humidity']!;
|
||||||
|
|
||||||
|
for (dynamic device_info_dyn in temperature_and_humidities) {
|
||||||
|
final Map<String, dynamic> device_info = device_info_dyn;
|
||||||
|
|
||||||
|
category.devices.add(await TemperatureHumidity.create(device_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.add(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dish_washer
|
||||||
|
{
|
||||||
|
final Category category = Category('dish_washer');
|
||||||
|
final List<dynamic> dish_washer = json['dish_washer']!;
|
||||||
|
|
||||||
|
for (dynamic device_info_dyn in dish_washer) {
|
||||||
|
final Map<String, dynamic> device_info = device_info_dyn;
|
||||||
|
|
||||||
|
category.devices.add(await DishWasher.create(device_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.add(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create washing_machines
|
||||||
|
{
|
||||||
|
final Category category = Category('washing_machines');
|
||||||
|
final List<dynamic> washing_machines = json['washing_machines']!;
|
||||||
|
|
||||||
|
for (dynamic device_info_dyn in washing_machines) {
|
||||||
|
final Map<String, dynamic> device_info = device_info_dyn;
|
||||||
|
|
||||||
|
category.devices.add(await WashingMachine.create(device_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.add(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CategoryWidget extends StatelessWidget {
|
||||||
|
final Category category;
|
||||||
|
|
||||||
|
CategoryWidget({super.key, required this.category});
|
||||||
|
|
||||||
|
String Name() {
|
||||||
|
return category.name
|
||||||
|
.split('_')
|
||||||
|
.map((s) => "${s[0].toUpperCase()}${s.substring(1)}")
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Wrap(
|
||||||
|
spacing: 25,
|
||||||
|
runSpacing: 25,
|
||||||
|
children:
|
||||||
|
category.devices.map((device) => device.create_widget()).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Device {
|
||||||
|
Widget create_widget();
|
||||||
|
}
|
14
frontend/lib/devices/dish_washer.dart
Normal file
14
frontend/lib/devices/dish_washer.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
|
||||||
|
import 'devices.dart';
|
||||||
|
|
||||||
|
class DishWasher extends Device {
|
||||||
|
static Future<DishWasher> create(Map<String, dynamic> device_info) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget create_widget() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
265
frontend/lib/devices/plug.dart
Normal file
265
frontend/lib/devices/plug.dart
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../constants.dart';
|
||||||
|
import 'devices.dart';
|
||||||
|
|
||||||
|
class Plug extends Device {
|
||||||
|
final String device_id;
|
||||||
|
String? device_descriptor;
|
||||||
|
bool led_state;
|
||||||
|
bool power_state;
|
||||||
|
double power_draw;
|
||||||
|
bool power_control;
|
||||||
|
|
||||||
|
static Future<Plug> create(Map<String, dynamic> device_info) async {
|
||||||
|
final String device_id = device_info['id'];
|
||||||
|
final String? device_descriptor = device_info['desc'];
|
||||||
|
final bool power_control = device_info['toggle'];
|
||||||
|
|
||||||
|
final response = await http
|
||||||
|
.get(Uri.parse("${Constants.BASE_URL}/plug_state/$device_id"));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception("Failed to fetch plug_state for $device_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, dynamic> device_state =
|
||||||
|
Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
||||||
|
|
||||||
|
return Plug(
|
||||||
|
device_id,
|
||||||
|
device_descriptor,
|
||||||
|
device_state["led"],
|
||||||
|
device_state["power"],
|
||||||
|
device_state["power_draw"],
|
||||||
|
power_control && device_state["power_draw"] < 15,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plug(this.device_id, this.device_descriptor, this.led_state, this.power_state,
|
||||||
|
this.power_draw, this.power_control);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget create_widget() {
|
||||||
|
const double header_height = 40;
|
||||||
|
const double info_height = 30;
|
||||||
|
const double info_width = 60;
|
||||||
|
const double x_offset = 0.9;
|
||||||
|
const double radius = 15;
|
||||||
|
|
||||||
|
return Table(
|
||||||
|
border: TableBorder(borderRadius: BorderRadius.circular(radius)),
|
||||||
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||||
|
columnWidths: const {
|
||||||
|
0: FixedColumnWidth(200.0),
|
||||||
|
1: FixedColumnWidth(200.0),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
TableRow(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.deepPurple[200],
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: header_height,
|
||||||
|
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(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(Icons.settings)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
]),
|
||||||
|
TableRow(children: [
|
||||||
|
SizedBox(
|
||||||
|
height: info_height,
|
||||||
|
child: Stack(children: [
|
||||||
|
const Align(
|
||||||
|
alignment: Alignment(-0.9, 0.0),
|
||||||
|
child: Text(
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
"LED")),
|
||||||
|
Align(
|
||||||
|
alignment: const Alignment(x_offset, 0.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: info_width,
|
||||||
|
child: PlugLed(
|
||||||
|
device_id: device_id, led_state: led_state))),
|
||||||
|
]))
|
||||||
|
]),
|
||||||
|
TableRow(children: [
|
||||||
|
SizedBox(
|
||||||
|
height: info_height,
|
||||||
|
child: Stack(children: [
|
||||||
|
const Align(
|
||||||
|
alignment: Alignment(-0.9, 0.0),
|
||||||
|
child: Text(
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
"Power")),
|
||||||
|
Align(
|
||||||
|
alignment: const Alignment(x_offset, 0.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: info_width,
|
||||||
|
child: PlugPower(
|
||||||
|
device_id: device_id,
|
||||||
|
power_state: power_state,
|
||||||
|
power_control: power_control))),
|
||||||
|
]))
|
||||||
|
]),
|
||||||
|
TableRow(children: [
|
||||||
|
SizedBox(
|
||||||
|
height: info_height,
|
||||||
|
child: Stack(children: [
|
||||||
|
const Align(
|
||||||
|
alignment: Alignment(-0.9, 0.0),
|
||||||
|
child: Text(
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
"Power Draw")),
|
||||||
|
Align(
|
||||||
|
alignment: const Alignment(x_offset, 0.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: info_width,
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.center, "$power_draw W")))
|
||||||
|
]))
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlugLed extends StatefulWidget {
|
||||||
|
final String device_id;
|
||||||
|
final bool led_state;
|
||||||
|
|
||||||
|
PlugLed({super.key, required this.device_id, required this.led_state});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PlugLed> createState() => PlugLedState(device_id, led_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlugLedState extends State<PlugLed> {
|
||||||
|
final String device_id;
|
||||||
|
bool led_state;
|
||||||
|
String _led_state_info;
|
||||||
|
|
||||||
|
PlugLedState(this.device_id, this.led_state)
|
||||||
|
: this._led_state_info = led_state ? "On" : "Off";
|
||||||
|
|
||||||
|
void _toggle_led_state() {
|
||||||
|
String target_state;
|
||||||
|
|
||||||
|
if (led_state) {
|
||||||
|
target_state = "off";
|
||||||
|
} else {
|
||||||
|
target_state = "on";
|
||||||
|
}
|
||||||
|
|
||||||
|
change_plug_state(device_id, "led", target_state).then((device_state) {
|
||||||
|
led_state = device_state["led"];
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_led_state_info = led_state ? "On" : "Off";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextButton(
|
||||||
|
onPressed: _toggle_led_state,
|
||||||
|
child: Text(textAlign: TextAlign.center, _led_state_info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlugPower extends StatefulWidget {
|
||||||
|
final String device_id;
|
||||||
|
final bool power_state;
|
||||||
|
final bool power_control;
|
||||||
|
|
||||||
|
PlugPower(
|
||||||
|
{super.key,
|
||||||
|
required this.device_id,
|
||||||
|
required this.power_state,
|
||||||
|
required this.power_control});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PlugPower> createState() =>
|
||||||
|
PlugPowerState(device_id, power_state, power_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlugPowerState extends State<PlugPower> {
|
||||||
|
final String device_id;
|
||||||
|
bool power_state;
|
||||||
|
String _power_state_info;
|
||||||
|
bool power_control;
|
||||||
|
|
||||||
|
PlugPowerState(this.device_id, this.power_state, this.power_control)
|
||||||
|
: this._power_state_info = power_state ? "On" : "Off";
|
||||||
|
|
||||||
|
void _toggle_power_state() {
|
||||||
|
String target_state;
|
||||||
|
|
||||||
|
if (power_state) {
|
||||||
|
target_state = "off";
|
||||||
|
} else {
|
||||||
|
target_state = "on";
|
||||||
|
}
|
||||||
|
|
||||||
|
change_plug_state(device_id, "power", target_state).then((device_state) {
|
||||||
|
power_state = device_state["power"];
|
||||||
|
|
||||||
|
power_control = device_state["power_draw"] < 15;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_power_state_info = power_state ? "On" : "Off";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (power_control) {
|
||||||
|
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(
|
||||||
|
String device_id, String module, String state) async {
|
||||||
|
var response = await http.post(
|
||||||
|
Uri.parse("${Constants.BASE_URL}/plug/$device_id/${module}_$state"));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception("Failed to post new state");
|
||||||
|
}
|
||||||
|
|
||||||
|
response =
|
||||||
|
await http.get(Uri.parse("${Constants.BASE_URL}/plug_state/$device_id"));
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception("Failed to fetch plug_state for $device_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Map.castFrom(jsonDecode(jsonDecode(response.body)));
|
||||||
|
}
|
16
frontend/lib/devices/temp_humid.dart
Normal file
16
frontend/lib/devices/temp_humid.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
|
||||||
|
import 'devices.dart';
|
||||||
|
|
||||||
|
class TemperatureHumidity extends Device {
|
||||||
|
static Future<TemperatureHumidity> create(
|
||||||
|
Map<String, dynamic> device_info) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget create_widget() {
|
||||||
|
// TODO: implement create_widget
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
15
frontend/lib/devices/thermostat.dart
Normal file
15
frontend/lib/devices/thermostat.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
|
||||||
|
import 'devices.dart';
|
||||||
|
|
||||||
|
class Thermostat extends Device {
|
||||||
|
static Future<Thermostat> create(Map<String, dynamic> device_info) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget create_widget() {
|
||||||
|
// TODO: implement create_widget
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
15
frontend/lib/devices/washing_machine.dart
Normal file
15
frontend/lib/devices/washing_machine.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
|
||||||
|
import 'devices.dart';
|
||||||
|
|
||||||
|
class WashingMachine extends Device {
|
||||||
|
static Future<WashingMachine> create(Map<String, dynamic> device_info) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget create_widget() {
|
||||||
|
// TODO: implement create_widget
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'devices.dart';
|
import 'devices/devices.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
|
|
Loading…
Reference in a new issue