Is there a way in Qt application framework to check if wifi is enabled? And does the way work for Android, iOS, macOS and Windows?
Note that I want to check if wifi is enabled or not. i don't bother if I have internet connectivity.
Environment:
Qt 5.12.x commercial version
You can iterate your QNetworkInterface instances (QT+=network in your .pro), and check the type() for a wireless interface, and also check the flags() to see if it is up and running. Example:
#include <QCoreApplication>
#include <QNetworkInterface>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
for(const QNetworkInterface& iface : QNetworkInterface::allInterfaces()) {
if (iface.type() == QNetworkInterface::Wifi) {
qDebug() << iface.humanReadableName() << "(" << iface.name() << ")"
<< "is up:" << iface.flags().testFlag(QNetworkInterface::IsUp)
<< "is running:" << iface.flags().testFlag(QNetworkInterface::IsRunning);
}
}
}
It should be cross-platform, but the documentation says that:
Not all operating systems support reporting all features. Only the
IPv4 addresses are guaranteed to be listed by this class in all
platforms. In particular, IPv6 address listing is only supported on
Windows, Linux, macOS and the BSDs.
There is no word about other attributes.
Related
Currently our tool uses QTCPSocket->ConnectToHost to connect to our TCP server, which works.
The problem arises when some of our machines are bridging two networks, across two entirely different IP ranges (10.x.x.x, 172.x.x.x). When you try to connect to a device on the 172.x.x.x network, it appears to be trying to connect via the 10.x network interface, and then times out and fails to connect. On windows, if you disable the network port for the 10.x network and reload the tool, it correctly uses the 172.x network interface and connects. I can see no way with QTCPSocket to force it to connect using a specific interface, or am I missing something? It seems like the 10.x network is getting priority somehow and we always try to use that when trying to establish an outgoing connection, which is not what we want.
Ideally, the user would be able to select what network interface they want to use to make the connection, whether its the 10.x or 172.x network.
This is using QT 5.15.0.
You can select the outgoing interface to use by calling bind() with your interfaces address first. This will select your outgoing address to use.
See the documentation for the bind function:
For TCP sockets, this function may be used to specify which interface to use for an outgoing connection, which is useful in case of multiple network interfaces.
I threw together a very simple demo for you:
Its all running locally. This is the servers main.cpp:
#include <QCoreApplication>
#include <QTcpServer>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTcpServer serv;
QObject::connect(&serv, &QTcpServer::newConnection, [](){
qDebug() << "New connection!";
});
qDebug() << serv.listen(QHostAddress("192.168.x.y"), 1337);
return a.exec();
}
And this is the clients main.cpp:
#include <QCoreApplication>
#include <QDebug>
#include <QTcpSocket>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTcpSocket s;
qDebug() << s.bind(QHostAddress("127.0.0.1"));
s.connectToHost(QHostAddress("192.168.x.y"), 1337);
return a.exec();
}
By calling bind we tell the client to send packets using the local interface, but as the server only listens to my wifi interface 192.168.x.y the connection will fail. If you now change the following line:
qDebug() << s.bind(QHostAddress("127.0.0.1"));
as such:
qDebug() << s.bind(QHostAddress("192.168.x.y"));
You will see that the server will recieve the connection, as we explicitly selected this interface to send from.
However, the operating system should select the correct interface for you (meaning in the demo: by not calling bind you should get a connection). If that does not happen you have a different issue.
To get a list of all available interfaces you can use QNetworkInterface::allInterfaces() which will grant you access to everything might you need to know.
We're a bunch of noobs trying to develop an ESP32 program that could be updated OTA with ESPHttpUpdate. The code we're using is the basic:
if((WiFi.status() == WL_CONNECTED)) {
t_httpUpdate_return ret = ESPhttpUpdate.update("https://url.to/my.bin");
switch(ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("HTTP_UPDATE_OK");
break;
}
}
In theory, it works. The program connects to WiFi, connects to the web server, downloads the new bin and flashes it successfully... Only in a loop. Once it downloads the new firmware, it flashes it, reboots the device, and starts all over again. I guess it's a simple question of getting it to recognize if the bin on the server is newer than the one on the device - but I can't seem to figure out how to do that :) Any pointers would be appreciated - Believe me I've googled a lot :)
Thank you in advance,
Seb
What you could do in it's firmware, is that it points to the next ''update'' link.
That file is only on the server when there's an update. When you update the firmware, just change the link to point to my2.bin etc.
So each firmware points to the next update (if available).
Example:
Current Firmware: my.bin
Points to: https://url.to/my1.bin
Current Firmware: my1.bin
Points to: https://url.to/my2.bin
etc
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#define APSSID "<YOUR-SSID>"
#define APPSK "<YOUR-PASSWD>"
ESP8266WiFiMulti WiFiMulti;
int FIRMWARE_VERSION = 1; // don't forget to Change this !!!. And save the .BIN to FirmwareV1.bin, FirmwareV2.bin etc...
void checkUpdate(int firmToCheck)
{
WiFiClient client;
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW); // Optional
ESPhttpUpdate.rebootOnUpdate(false); // Manual reboot after Update
String urlUPD = "http://192.168.1.100:8080/FirmwareV" + String(firmToCheck + 1) + ".bin";
t_httpUpdate_return ret = ESPhttpUpdate.update(client, urlUPD);
if (ret == HTTP_UPDATE_OK){
Serial.println("HTTP_UPDATE_OK. Reboot");
delay(1000); // Wait a second and restart
ESP.restart();
}
}
void setup(){
Serial.begin(115200);
Serial.println();
// Classic wifi connexion here. More or less complicated
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(APSSID, APPSK);
delay(5000);
Serial.print("Firmware version : ");
Serial.println(FIRMWARE_VERSION);
checkUpdate(FIRMWARE_VERSION);
// if not Server found, or not file found etc... move next
}
void loop() {
// normal stuff here !!!
//of course any time, we can do something like this : if (blablala) checkUpdate(FIRMWARE_VERSION);
}
# miken32
Sorry.
This is the KISS version of "Updating a ESP8266 or ESP32 from a Web Server" and solves the problem of devices that constantly reboot after an update: the version number indicated in the code is the same as the file on the Server (The Version number is concatenated with the file name) and the code searches at each reboot the file of the "next version". If present, firmware update and reboot. If it is absent, the code continues normally.
Ex: for "int FIRMWARE_VERSION = 1;" you must place on the server a file which will be called for example "Update_my_ESPV2.bin", concatenation of "Update_my_ESPV" + the next FIRMWARE_VERSION + ".bin"
In this new file "Update_my_ESPV2.bin", int FIRMWARE_VERSION is set to 2. At the next reboot, this firmware will search the file "Update_my_ESPV3.bin" on the Server... etc etc....
I use this process without any trouble with a Standalone Http Server (Rebex Tiny WebServer).
http://192.168.1.100:8080/ is the IP and Port of the Server. (For example). It can be anywhere. Local or remote network
On the web I've seen dozens of answers about updating via HTTP, all more complicated than that. Some solutions used a database.
This solution is much simpler , and much shorter code. Of couse, we can do better from a security point of view, but this is suitable for most uses.
Sorry for my English. I'm French ;)
ZJP
Qt Version 5.10.0 (MSVC 2015, 32bit)
I have a PC which has a static host address("192.168.0.106"), and a device with an arbitrary IP address assigned by a router. I want to establish a UDP connection between them.
Qt has a udp demo called multicastreceiver, I modified the Receiver::processPendingDatagrams() function as followed:
QByteArray datagram;
QHostAddress senderIP = QHostAddress();
quint16 portx = 0;
while (udpSocket.hasPendingDatagrams()) {
datagram.resize(int(udpSocket.pendingDatagramSize()));
udpSocket.readDatagram(datagram.data(), datagram.size(), &senderIP, &portx);
statusLabel->setText(tr("Received datagram: \"%1\" # %2:%3")
.arg(datagram.constData())
.arg(senderIP.toIPv4Address())
.arg(portx));
}
and in the construction function:
udpSocket.bind(QHostAddress::AnyIPv4, 18427, QUdpSocket::ShareAddress);
connect(&udpSocket, SIGNAL(readyRead()),
this, SLOT(processPendingDatagrams()));
I successfully received the udp message, but
senderIP.toIPv4Address() is 0, and senderIP.toString is NULL
portx is 64800 but it is wrong
Could anyone please tell me what is wrong with these codes?
PS: I can get udp message and sender IP address and the right port number via a UDP debug tool(a PC program).
I think you've found a known bug in Qt:
https://bugreports.qt.io/browse/QTBUG-64784
This is fixed in Qt 5.9.4 - and I believe in 5.10.1 also.
See also the commit.
Good evening,
my project is to create a desktop application.
This application will allow me to communicate from the PC to an stm32 microcontroller via the usb port.
I use the class: QSerialPort available on Qt
I want to know the number of USB port connected on my PC.
Here is my code:
#include <QCoreApplication>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
Int main (int argc, char * argv [])
{
QCoreApplication a (argc, argv);
QDebug () << "Number of serial ports:" << QSerialPortInfo :: availablePorts (). Count ();
Return 0;
}
So I plugged my microcontroller stm32f4, an external hard drive with a usb cable ...
My problem is this: When I run the program under Qt there is no compilation problem but the result of the debug shows me the following line: "Number of serial ports: 0" Usb ports connected.
Following the activation of bluetooth or the insertion of a 3g key there is detection of these ports, but the others remain undetected.
I didn't understand where the mistake comes from !!
Qt only has native support for USB Serial ports. (eg: COM/TTY)
If you want to know low level details (eg: physical port number) of the USB port the STM is connected to, you have to use platform specific code.
Libusb can help you with that.
My Qt application needs to uniquely identify computers it runs on. To achieve that, my current code probes its mac address using QNetworkInterface class like this:
QNetworkInterface intf;
#ifdef Q_WS_MAC
intf = QNetworkInterface::interfaceFromName(QString("en0"));
#endif
#ifdef Q_WS_WIN
intf = QNetworkInterface::interfaceFromIndex(0);
#endif
if(intf.isValid())
QString mac_address = intf.hardwareAddress();
It seems to work on the few machines I have tested it on. But is the above strategy guaranteed to work on all machines? For example, can one rename the interface name to something different from "en0" on a Mac? If so, is there a better way to probe the mac address for the interface that will not change over time?