ich habe ein kleines PicoC* geschrieben, mit der man eine Anwesenheitserkennung nur mit der Fritzbox realisieren kann. Das Ganze ist bei weitem noch nicht fertig, eher ein Proof of Concept. Aber da es schon ewig bei mir liegt und die Zeit für einen richtigen Artikel fehlt, wollte ich es jetzt doch mal kurz vorstellen. Vlt hilft es ja jemanden. So wie es ist läuft es bei mir schon einige Monate.
// write program here in PicoC // CheckFritzIPs // (C) 2017 Mighty - see loxforum.com // based on: https://groups.google.com/forum/#!topic/loxone-english/KZNGlIQz4qU #define SLEEP_TIME 2000 #define BUFF_SIZE 40001 #define RD_BLOCK_SIZE 128 #define DEBUG_LEVEL 0 // 0 = disable ; 1 = INFO ; 2 = DEBUG char* host = "192.168.2.1"; // The API URL // Global variables char value[50]; char data[BUFF_SIZE]; int debug_msg_count = 0; char* position = 0; // Helper methods void downloadDataForMac(char* mac) { char device[255]; sprintf(device, "/dev/tcp/%s/49000", host); if (DEBUG_LEVEL > 1 ) printf("%d: downloadData device %s", debug_msg_count++, device); char headers[1024]; sprintf(headers, "POST /upnp/control/Hosts HTTP/1.1\r\nCONNECTION: close\r\nContent-Length: 295\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPACTION: \"urn:dslforum-org:service:Hosts:1#GetSpecificHostEntry\"\r\n\r\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:GetSpecificHostEntry xmlns:u=\"urn:dslforum-org:service:Hosts:1\"><NewMACAddress>%s</NewMACAddress></u:GetSpecificHostEntry></s:Body></s:Envelope>\r\n ", mac); if (DEBUG_LEVEL > 1 ) printf("%d: downloadData headers %s", debug_msg_count++, headers); STREAM* tcpStream = stream_create(device, 0, 0); if (DEBUG_LEVEL > 1 ) printf("%d: downloadData tcpStream %d", debug_msg_count++, (int)tcpStream); stream_write(tcpStream, headers, strlen(headers)); stream_flush(tcpStream); char block[RD_BLOCK_SIZE]; int count; int i = 0; // read stream do { count = stream_read(tcpStream, block, RD_BLOCK_SIZE, 4000); if (DEBUG_LEVEL > 1 ) printf("%d: downloadData count %d", debug_msg_count++, (int)count); if (count > 0) strncpy((char*)data + i * RD_BLOCK_SIZE, block, count); i++; if (i >= ( ( BUFF_SIZE - 1 ) / RD_BLOCK_SIZE )) count = 0; // avoid buffer overflows } while (count > 0); stream_close(tcpStream); data[BUFF_SIZE] = 0; //put null character or end of string at the end. } int moveToKey(char* key) { if (DEBUG_LEVEL > 1 ) sleep(250); //provide time to output log entries, otherwise log entries get lost ?! char* newPos = strstr(position, key); if (newPos != NULL) { position = newPos; if (DEBUG_LEVEL > 1 ) printf("%d: found key %s, pos %d", debug_msg_count++, key, (int)position); return 1; } else { if (DEBUG_LEVEL > 1 ) printf("%d: NOT FOUND key %s", debug_msg_count++, key); return 0; } } char* readStringValue(char* key, int stripEnd) { value[49] = '\0'; if (moveToKey(key) > 0) { char* valueStart = (char*)((int)position + strlen(key)); int valueLen = strfind(valueStart, "</", 0); if (valueLen - stripEnd > 48) { // Prevent error with occasional long (weird?) value of e.g. 'humidity', which produces the following error: // myweather:93:14 can't assign char* from if (DEBUG_LEVEL > 1 ) printf("%d: DATA TOO LARGE (readStringValue): length=%d", debug_msg_count++, valueLen); } else { if (valueLen - stripEnd > 0) { strncpy(value, valueStart, valueLen - stripEnd); if (DEBUG_LEVEL > 1 ) printf("%d: found value of %s = %s (l=%d,s=%d)", debug_msg_count++, key, value, valueLen, stripEnd); } else { if (DEBUG_LEVEL > 1 ) printf("%d: DATA SEEMS INCOMPLETE (readStringValue)", debug_msg_count++); } } } if (DEBUG_LEVEL > 1 ) printf("%d: returning value %s", debug_msg_count++, value); return value; } int readIntValue(char* key) { return batoi(readStringValue(key, 0)); } float readFloatValue(char* key) { return batof(readStringValue(key, 0)); } float readPercentageValue(char* key) { return batof(readStringValue(key, 1)); } //////////////////////////////////////////////////////// // Start while(1) { if (DEBUG_LEVEL > 1 ) printf("CheckFritzIPs"); downloadDataForMac("AA:BB:CC:DD:EE:FF"); position = data; char* sNewIPAddress = readStringValue("<NewIPAddress>", 0); if (DEBUG_LEVEL > 1 ) printf("%d: NewIPAddress %s", debug_msg_count++, sNewIPAddress); int iNewActive = readIntValue("<NewActive>"); if (DEBUG_LEVEL > 1 ) printf("%d: NewActive %d", debug_msg_count++, iNewActive); char* sNewHostName = readStringValue("<NewHostName>", 0); if (DEBUG_LEVEL > 1 ) printf("%d: NewHostName %s", debug_msg_count++, sNewHostName); if (DEBUG_LEVEL > 1 ) printf("CheckFritzIPs - end"); setoutput(0, iNewActive); sleep(SLEEP_TIME); }
Ich wollte es immer mal umbauen, dass man ein Array von MACs angeben kann und dann die entsprechenden Ausgänge geschaltet werden. Wie gesagt, vlt macht das ja jemand noch.
Viel Spaß mit dem Code.
Grüße Mighty
*
Teile des Codes sind von woanders, leider weiß ich nach der langen Zeit nicht mehr, woher sie kommen. :-(
Kommentar