Arduino и Xiaomi Mi Home
- Войдите на сайт для отправки комментариев
Доброго всем времени суток. Пытаюсь научить ардуинку работать с MiHome, в частности с Gateway на котором включен режим разработчика. В этом режиме Gateway шлет по UDP броадкастом репорты о своем состоянии. Ардуинка в упор не хочет их парсить.
Вот что выдает Wirenshark: source ip с которго идет вещание - 192.168.2.103 (совпадает с тем, что в настройках Gateway), destination ip - 224.0.0.50 - широковещательный ip - никак не настраивается, Gateway его сам устанавливает., Destination port - 9898, порт, на который идут посылки.
Скетч из коробки, поменял только ip и порт прослушки
#include <Ethernet.h>
#include <EthernetUdp.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 2, 10);
IPAddress gate(192, 168, 2, 1);
IPAddress dns(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 1);
unsigned int localPort = 9898; // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged"; // a string to send back
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
//Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
// start the Ethernet
//Ethernet.begin(mac, ip);
Ethernet.begin(mac, ip, dns, gate, subnet);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// start UDP
int in = Udp.begin(localPort);
Serial.println("Start "+String(in));
}
void loop() {
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if (packetSize) {
Serial.print("Received packet of size ");
Serial.println(packetSize);
Serial.print("From ");
IPAddress remote = Udp.remoteIP();
for (int i=0; i < 4; i++) {
Serial.print(remote[i], DEC);
if (i < 3) {
Serial.print(".");
}
}
Serial.print(", port ");
Serial.println(Udp.remotePort());
// read the packet into packetBufffer
Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
Serial.println(packetBuffer);
// send a reply to the IP address and port that sent us the packet we received
// Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
// Udp.write(ReplyBuffer);
// Udp.endPacket();
}
delay(10);
}
и в сериале ничего, пусто(((
и что делать ума не приложу. Вопрос к знатокам, широковещательные сообщения имеют какие-то спец настройки, с которыми библиотека EthernetUDP не умеет работать, или у меня руки кривые.
От безысходности накидал простенькую программку, проверить, что udp на ардуинке вообще работает, так если кидать пакет напрямую на ардуинку, то все работает, как только ставлю broadcast - глухо((
Вопрос решился.
Инфа для тех, кто вдруг столкнется с подобным:
Теория: оказывается, чтобы начать слушать мультикаст пакеты нужно присоединиться к мультикаст группе.
Практика: в стандартной библиотеке Ethernet уже есть метод для этого.
Вот скетч
/* UDPSendReceiveString: This sketch receives UDP message strings, prints them to the serial port and sends an "acknowledge" string back to the sender A Processing sketch is included at the end of file that can be used to send and received messages for testing with a computer. created 21 Aug 2010 by Michael Margolis This code is in the public domain. */ #include <Ethernet.h> #include <EthernetUdp.h> // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 2, 177); IPAddress multi_ip(224, 0, 0, 50); unsigned int localPort = 9898; // local port to listen on // buffers for receiving and sending data char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet, char ReplyBuffer[] = "acknowledged"; // a string to send back // An EthernetUDP instance to let us send and receive packets over UDP EthernetUDP Udp; void setup() { // You can use Ethernet.init(pin) to configure the CS pin //Ethernet.init(10); // Most Arduino shields //Ethernet.init(5); // MKR ETH shield //Ethernet.init(0); // Teensy 2.0 //Ethernet.init(20); // Teensy++ 2.0 //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet // start the Ethernet Ethernet.begin(mac, ip); // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } // Check for Ethernet hardware present if (Ethernet.hardwareStatus() == EthernetNoHardware) { Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); while (true) { delay(1); // do nothing, no point running without Ethernet hardware } } if (Ethernet.linkStatus() == LinkOFF) { Serial.println("Ethernet cable is not connected."); } // start UDP Udp.beginMulticast(multi_ip, localPort); } void loop() { // if there's data available, read a packet int packetSize = Udp.parsePacket(); if (packetSize) { Serial.print("Received packet of size "); Serial.println(packetSize); Serial.print("From "); IPAddress remote = Udp.remoteIP(); for (int i=0; i < 4; i++) { Serial.print(remote[i], DEC); if (i < 3) { Serial.print("."); } } Serial.print(", port "); Serial.println(Udp.remotePort()); // read the packet into packetBufffer Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); Serial.println("Contents:"); Serial.println(packetBuffer); // send a reply to the IP address and port that sent us the packet we received Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); Udp.write(ReplyBuffer); Udp.endPacket(); } delay(10); } /* Processing sketch to run with this example ===================================================== // Processing UDP example to send and receive string data from Arduino // press any key to send the "Hello Arduino" message import hypermedia.net.*; UDP udp; // define the UDP object void setup() { udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 //udp.log( true ); // <-- printout the connection activity udp.listen( true ); // and wait for incoming message } void draw() { } void keyPressed() { String ip = "192.168.1.177"; // the remote IP address int port = 8888; // the destination port udp.send("Hello World", ip, port ); // the message to send } void receive( byte[] data ) { // <-- default handler //void receive( byte[] data, String ip, int port ) { // <-- extended handler for(int i=0; i < data.length; i++) print(char(data[i])); println(); } */да, кстати, похоже в библиотеке Ethernet.h закралась ошибочка, константа
#define UDP_TX_PACKET_MAX_SIZE 24
как-то уж больно маленький буфер, из-за этого пакеты не целые приходили.
поменял на
#define UDP_TX_PACKET_MAX_SIZE 1024
и все заработало нормально