Я пытаюсь написать приложение флаттера для приложения IoT. Мобильное устройство будет подключаться к оборудованию через Wi-Fi, а данные будут отправляться через TCP-сокет. Оборудование IoT находится в разработке, но мне нужно начать работу с приложением.
Мне немного помог сценарий python, который запускает сокет и выводит 2 синусоидальные волны, которые были слегка рандомизированы. Он работает хорошо, и у меня есть сценарий хоста python, который подключается к нему и отображает данные по мере их поступления. Я собираюсь притвориться, что это данные датчика, поэтому я хочу подключиться к нему с помощью флаттера, чтобы я мог начать работать над своим пользовательским интерфейсом et c.
Я пробовал 1000 вещей, но в основном работал над этим: https://flutter.dev/docs/cookbook/networking/web-sockets.
Еще я пробовал использовать nodejs с socket.io, и мне удалось связаться с flutter с помощью пакета adhara_socket_io, но там так много абстракции, что я беспокоюсь, что это не реплицирует то, что я получу. наше оборудование.
Вот код python:
import queue
import time
#import matplotlib.pyplot as plt
import math
from queue import Queue
import numpy as np
import random
import socket
import threading
import asyncio
# A Queue in which the wave threads will store their values
# We will use this queue to get the data we need to send to our clients
Q = queue.Queue()
# replace this with your own host ip
HOST = '192.168.0.13'
PORT = 65432
Afrequency = float(input('give the frequency of the data output wave A: '))
Aperiod = int(input('give the output period (multiples of pi) of wave A: '))
Bfrequency = float(input('give the frequency of data output wave B: '))
Bperiod = int(input('give the output period (multiples of pi) of wave B: '))
# this function will continuosly generate x and y values for a given sine wave
# it waits 1/freq seconds so our frequency matches the given input
def generateTuples(name, outputfrequency, outputperiod):
sincurveshift = 10
rmax = 1.25
rmin = 0.75
outputperiod = outputperiod * math.pi
numberOfPoints = outputfrequency * outputperiod
increment = (2 * math.pi) / numberOfPoints
xcounter = 0
while True:
jitterValue = rmin + (random.random() * (rmax - rmin))
x = xcounter * increment
sinValue = 5 * math.sin(x) + sincurveshift * jitterValue
partOfTheMessage = '%s(%09.2f,%09.2f)*' % (name, x, sinValue)
xcounter += 1
Q.put(partOfTheMessage)
time.sleep(1/outputfrequency)
# this is a thread that will be created each time a client connects
# it sends the total string with values from wave A and B
class clientThread(threading.Thread):
def __init__(self, clientAddress, clientSocket, q):
threading.Thread.__init__(self)
self.clientSocket = clientSocket
print("New client connected with address: " + str(clientAddress))
def run(self):
while True:
self.clientSocket.send(bytes(Q.get(), 'utf-8'))
time.sleep(0.1)
def main():
# first we start up 2 threads that will each generate a y value every 1/freq seconds
# we let them run in the background so we can move on to listening for clients
print('starting sine wave 1')
print('starting sine wave 2')
wave1 = threading.Thread(target=generateTuples, args=(
'A', Afrequency, Aperiod), daemon=True)
wave2 = threading.Thread(target=generateTuples, args=(
'B', Bfrequency, Bperiod), daemon=True)
wave1.start()
wave2.start()
time.sleep(1)
print('starting transmission')
# here we set up the host
# we continously look for clients and give each of them their own thread
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen()
while True:
conn, addr = s.accept()
client = clientThread(addr, conn, queue)
client.start()
if __name__ == "__main__":
main()
А вот мой код флаттера.
import 'package:flutter/foundation.dart';
import 'package:web_socket_channel/io.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MyApp Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'MyApp Mobile'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final channel = IOWebSocketChannel.connect('ws://192.168.0.13:65432');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: StreamBuilder(
stream: channel.stream,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
case ConnectionState.none:
print('trying to connect');
return LinearProgressIndicator();
case ConnectionState.active:
print("OMG ITS CONNECTED");
print(snapshot.data);
return Text(snapshot.data);
case ConnectionState.done:
return Text('Its done ${snapshot.data}');
}
return Text(snapshot.hasData ? '${snapshot.data}' : 'No Data');
},
)),
);
}
}
Я использую свой телефон для запуска разрабатываемого приложения - не уверен, что это имеет значение. Любая помощь приветствуется!
N
EDIT - теперь я вижу ошибку в консоли python:
New client connected with address: ('192.168.0.16', 65020)
Exception in thread Thread-24:
Traceback (most recent call last):
File "C:\Users\nickc\AppData\Local\Programs\Python\Python38-32\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "host.py", line 62, in run
self.clientSocket.send(bytes(Q.get(), 'utf-8'))
ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine
Так что похоже, что он подключается а затем прерывает соединение?
Как уже упоминалось shubham в одном из ответов, я могу успешно подключиться и распечатать входящие данные на консоли с помощью:
Socket socket = await Socket.connect(host, port);
socket.listen((event) {
print(String.fromCharCodes(event));
});