Skip to content

Commit 58844e0

Browse files
committed
Merge branch 'rhecker/openvino_25.1.0' of github.com:openvinotoolkit/openvino_testdrive into rhecker/openvino_25.1.0
2 parents 917619c + 8cac442 commit 58844e0

File tree

5 files changed

+353
-49
lines changed

5 files changed

+353
-49
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
import 'dart:convert';
2+
3+
import 'package:fluent_ui/fluent_ui.dart';
4+
import 'package:flutter/services.dart';
5+
import 'package:inference/annotation.dart';
6+
import 'package:mqtt_client/mqtt_client.dart';
7+
import 'package:mqtt_client/mqtt_server_client.dart';
8+
9+
class MqttClientWrapper {
10+
final MqttServerClient client;
11+
final String topic;
12+
final bool retain;
13+
14+
const MqttClientWrapper({required this.client, required this.topic, required this.retain});
15+
16+
void publish(String data) {
17+
if (client.connectionStatus?.state == MqttConnectionState.connected){
18+
final builder = MqttClientPayloadBuilder();
19+
builder.addString(data);
20+
client.publishMessage(topic, MqttQos.exactlyOnce, builder.payload!, retain: retain);
21+
}
22+
}
23+
24+
void disconnect() {
25+
client.disconnect();
26+
}
27+
}
28+
29+
class AutomationOptions extends StatefulWidget {
30+
final Stream<ImageInferenceResult> stream;
31+
32+
const AutomationOptions({required this.stream, super.key});
33+
34+
@override
35+
State<AutomationOptions> createState() => _AutomationOptionsState();
36+
}
37+
38+
class _AutomationOptionsState extends State<AutomationOptions> {
39+
40+
MqttClientWrapper? client;
41+
42+
void publishToMqtt(ImageInferenceResult result) {
43+
if (client != null && result.json != null) {
44+
client!.publish(jsonEncode(result.json!));
45+
}
46+
}
47+
48+
@override
49+
void initState() {
50+
super.initState();
51+
widget.stream.listen(publishToMqtt);
52+
}
53+
54+
@override
55+
void dispose() {
56+
super.dispose();
57+
client?.disconnect();
58+
}
59+
60+
@override
61+
Widget build(BuildContext context) {
62+
return Row(
63+
children: [
64+
OutlinedButton(
65+
style: ButtonStyle(
66+
shape:WidgetStatePropertyAll(RoundedRectangleBorder(
67+
borderRadius: BorderRadius.circular(4.0),
68+
side: const BorderSide(color: Color(0XFF545454)),
69+
)),
70+
),
71+
onPressed: () async {
72+
print("open dialog");
73+
if (client != null) {
74+
client?.disconnect();
75+
setState(() {
76+
client = null;
77+
});
78+
} else {
79+
final newClient = await showDialog<MqttClientWrapper?>(
80+
context: context,
81+
builder: (context) => AutomationOptionsDialog()
82+
);
83+
84+
print("New client: $newClient");
85+
86+
setState(() {
87+
client = newClient;
88+
});
89+
}
90+
},
91+
child: Text((client == null ? "Connect to MQTT Broker": "Disconnect")),
92+
),
93+
],
94+
);
95+
}
96+
}
97+
98+
class AutomationOptionsDialog extends StatefulWidget {
99+
const AutomationOptionsDialog({super.key});
100+
101+
@override
102+
State<AutomationOptionsDialog> createState() => _AutomationOptionsDialogState();
103+
}
104+
105+
class _AutomationOptionsDialogState extends State<AutomationOptionsDialog> {
106+
final TextEditingController _hostController = TextEditingController(text: "");
107+
final TextEditingController _portController = TextEditingController(text: "1883");
108+
final TextEditingController _usernameController = TextEditingController(text: "");
109+
final TextEditingController _passwordController = TextEditingController(text: "");
110+
final TextEditingController _topicController = TextEditingController(text: "");
111+
112+
bool retain = false;
113+
bool loading = false;
114+
115+
List<String> errors = [];
116+
117+
void connect() async {
118+
final client = MqttServerClient.withPort(_hostController.text, "test drive", int.parse(_portController.text));
119+
setState(() { loading = true; errors = []; });
120+
client.connect(_usernameController.text, _passwordController.text)
121+
.then((status) {
122+
setState(() { loading = false; });
123+
print(status.toString());
124+
if (status?.state == MqttConnectionState.connected) {
125+
if (mounted) {
126+
Navigator.pop(context, MqttClientWrapper(client: client, retain: retain, topic: _topicController.text));
127+
return;
128+
}
129+
}
130+
MqttUtilities.asyncSleep(3).then((_) => client.disconnect); // ensure the client is disconnected on error
131+
})
132+
.onError((e, stacktrace) {
133+
setState(() {
134+
errors.add(e.toString());
135+
loading = false;
136+
});
137+
print("Error: $e: \n $stacktrace") ;
138+
});
139+
}
140+
141+
@override
142+
void dispose() {
143+
super.dispose();
144+
145+
_hostController.dispose();
146+
_portController.dispose();
147+
_usernameController.dispose();
148+
_passwordController.dispose();
149+
_topicController.dispose();
150+
}
151+
152+
@override
153+
Widget build(BuildContext context) {
154+
return ContentDialog(
155+
constraints: const BoxConstraints(
156+
maxWidth: 756,
157+
maxHeight: 500,
158+
),
159+
title: const Text('Connect to MQTT Broker'),
160+
content: Column(
161+
crossAxisAlignment: CrossAxisAlignment.start,
162+
children: [
163+
Expanded(
164+
child: Column(
165+
children: [
166+
Row(
167+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
168+
children: [
169+
SizedBox(
170+
width: 600,
171+
child: InfoLabel(
172+
label: "Host",
173+
child: TextBox(
174+
placeholder: "",
175+
controller: _hostController,
176+
onChanged: (_) {},
177+
)
178+
),
179+
),
180+
SizedBox(
181+
width: 100,
182+
child: InfoLabel(
183+
label: "Port",
184+
child: TextBox(
185+
keyboardType: TextInputType.number,
186+
inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
187+
placeholder: "",
188+
controller: _portController,
189+
onChanged: (_) {},
190+
)
191+
),
192+
),
193+
],
194+
),
195+
SizedBox(height: 10),
196+
InfoLabel(
197+
label: "Username",
198+
child: TextBox(
199+
placeholder: "",
200+
controller: _usernameController,
201+
onChanged: (_) {},
202+
)
203+
),
204+
SizedBox(height: 10),
205+
InfoLabel(
206+
label: "Password",
207+
child: TextBox(
208+
placeholder: "",
209+
controller: _passwordController,
210+
onChanged: (_) {},
211+
)
212+
),
213+
SizedBox(height: 10),
214+
Row(
215+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
216+
children: [
217+
SizedBox(
218+
width: 600,
219+
child: InfoLabel(
220+
label: "Topic",
221+
child: TextBox(
222+
placeholder: "",
223+
controller: _topicController,
224+
onChanged: (_) {},
225+
)
226+
),
227+
),
228+
SizedBox(
229+
width: 100,
230+
child: InfoLabel(
231+
label: "Retain",
232+
child: ToggleSwitch(
233+
onChanged: (v) { setState(() { retain = v; });},
234+
checked: retain,
235+
),
236+
),
237+
),
238+
239+
],
240+
)
241+
],
242+
),
243+
),
244+
Column(
245+
children: <Widget>[
246+
for (var error in errors) Text(error)
247+
]
248+
),
249+
Row(
250+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
251+
children: [
252+
SizedBox(
253+
width: 500,
254+
child: (loading ? ProgressBar() : Container())
255+
),
256+
Row(
257+
mainAxisAlignment: MainAxisAlignment.end,
258+
children: [
259+
Button(
260+
onPressed: () => Navigator.pop(context),
261+
child: const Text("Cancel"),
262+
),
263+
const SizedBox(width: 10),
264+
FilledButton(
265+
onPressed: connect,
266+
child: const Text("Connect"),
267+
),
268+
],
269+
),
270+
],
271+
)
272+
],
273+
)
274+
);
275+
}
276+
}

0 commit comments

Comments
 (0)