You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
826 lines
21 KiB
826 lines
21 KiB
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <openssl/md5.h>
|
|
#include <unistd.h>
|
|
#include <iconv.h>
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/parser.h>
|
|
#include <UDPTCPNetwork.h>
|
|
#include <math.h>
|
|
|
|
#include "fbsh.h"
|
|
|
|
/*
|
|
* implementation of the function atoi and atof but with additional check for NULL pointer
|
|
* atoi_check will return fallback value on error
|
|
* atof will return NAN
|
|
*/
|
|
double atof_check (char *s) {
|
|
if (s != NULL) return (atof(s));
|
|
return NAN;
|
|
}
|
|
|
|
|
|
int atoi_check (char *s, int failnumber) {
|
|
if (s != NULL) return (atoi(s));
|
|
return failnumber;
|
|
}
|
|
|
|
|
|
std::string generateMD5 (char* input, int size) {
|
|
int i;
|
|
MD5_CTX md5;
|
|
unsigned char out[MD5_DIGEST_LENGTH];
|
|
char txt[32];
|
|
std::string md5sum = "";
|
|
|
|
MD5_Init(&md5);
|
|
MD5_Update(&md5, input, size);
|
|
MD5_Final(out, &md5);
|
|
|
|
for ( i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
|
snprintf (txt, 32, "%02x", out[i]);
|
|
md5sum += txt;
|
|
}
|
|
|
|
return md5sum;
|
|
}
|
|
|
|
|
|
FBSmartHome::FBSmartHome() {
|
|
hostname = "";
|
|
SID = "00 not yet set 00";
|
|
fsidfile = NULL;
|
|
}
|
|
|
|
|
|
FBSmartHome::~FBSmartHome() {
|
|
if (fsidfile != NULL) CloseSIDFile();
|
|
}
|
|
|
|
|
|
/*
|
|
* try to connect with the last known SID.
|
|
*/
|
|
int FBSmartHome::Connect(std::string host) {
|
|
int len;
|
|
xmlDocPtr xmldoc;
|
|
xmlNodePtr xmlnode;
|
|
|
|
hostname = host;
|
|
|
|
// is sid working?
|
|
len = tcp.WebGetFile(hostname+"/login_sid.lua?sid="+SID, inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"SessionInfo"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
while (xmlchild) {
|
|
if ((!xmlStrcmp(xmlchild->name, (const xmlChar *)"SID")))
|
|
SID = (char *)xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
if (SID.compare("0000000000000000") == 0) {
|
|
hostname = "";
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
|
|
errno = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int FBSmartHome::XMLPrepare(char *buffer, int len, xmlDocPtr *xmldoc, xmlNodePtr *xmlnode) {
|
|
//
|
|
// read the xml data from memory and select root node.
|
|
if (xmldoc == NULL || xmlnode == NULL) return -1;
|
|
|
|
*xmldoc = xmlReadMemory(inbuffer, len, "hostname", NULL, 0);
|
|
if (xmldoc == NULL) {
|
|
fprintf (stderr, "%s: Could not read XML Document\n", __FUNCTION__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
|
|
*xmlnode = xmlDocGetRootElement(*xmldoc);
|
|
if (*xmlnode == NULL) {
|
|
fprintf (stderr, "%s: Empty XML Document\n", __FUNCTION__);
|
|
xmlFreeDoc(*xmldoc);
|
|
errno = EOF;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* connect with username and password, if connect is successfull the
|
|
* SID will be returned.
|
|
*/
|
|
#define PWSSIZE 512
|
|
int FBSmartHome::Connect (std::string host, std::string username, std::string password) {
|
|
int len;
|
|
xmlDocPtr xmldoc;
|
|
xmlNodePtr xmlnode;
|
|
std::string challenge;
|
|
std::string formdata;
|
|
|
|
hostname = host;
|
|
SID = "";
|
|
tcp.Close();
|
|
|
|
//
|
|
// get challenge from FritzBox
|
|
len = tcp.WebGetFile(hostname+"/login_sid.lua", inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"SessionInfo"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
while (xmlchild) {
|
|
if ((!xmlStrcmp(xmlchild->name, (const xmlChar *)"SID")))
|
|
SID = (char *)xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
else if ((!xmlStrcmp(xmlchild->name, (const xmlChar *)"Challenge")))
|
|
challenge = (char*) xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
//
|
|
// create Challenge-PSW -> MD5 sum
|
|
//
|
|
|
|
//
|
|
// convert to UTF16_LE
|
|
std::string convertfrom = challenge+"-"+password;
|
|
char *conv_input = (char *)convertfrom.c_str();
|
|
size_t conv_inbytes = strlen (conv_input);
|
|
size_t conv_size;
|
|
char convertedpsw[PWSSIZE];
|
|
char *conv_output = (char*)convertedpsw;
|
|
size_t conv_outbytes = PWSSIZE;
|
|
|
|
iconv_t ic = iconv_open("UTF-16LE", "UTF-8");
|
|
if ((long int)ic == -1) {
|
|
fprintf (stderr, "iconv_open error: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
conv_size = iconv(ic, &conv_input, &conv_inbytes, (char**)&conv_output, &conv_outbytes);
|
|
if ((long int)conv_size == -1) {
|
|
fprintf (stderr, "iconv error: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
iconv_close(ic);
|
|
|
|
//
|
|
// create password
|
|
formdata = "response="+challenge+"-"+generateMD5(convertedpsw, conv_output-convertedpsw)+"&username="+username;
|
|
len = tcp.WebGetFile(hostname+"/login_sid.lua", inbuffer, FB_BUFFER, (char*)formdata.c_str());
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"SessionInfo"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
while (xmlchild) {
|
|
if ((!xmlStrcmp(xmlchild->name, (const xmlChar *)"SID")))
|
|
SID = (char *)xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
else if ((!xmlStrcmp(xmlchild->name, (const xmlChar *)"Challenge")))
|
|
challenge = (char*) xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
errno = 0;
|
|
return 0;
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* read sidfile, if it does not exist create file.
|
|
*/
|
|
#define BUFSIZE 1024
|
|
int FBSmartHome::UseSIDFile(std::string fn) {
|
|
char buffer[BUFSIZE];
|
|
int i;
|
|
|
|
if ((fsidfile = fopen (fn.c_str(), "r+")) == NULL) {
|
|
// file not found create file
|
|
if ((fsidfile = fopen (fn.c_str(), "w")) == NULL) {
|
|
fprintf (stderr, "error on writing sidfile '%s' : %s\n", fn.c_str(),
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
// sidfile found and open
|
|
fseek (fsidfile, 0, SEEK_SET);
|
|
if (fgets(buffer, BUFSIZE, fsidfile) != NULL) {
|
|
buffer[BUFSIZE] = '\0';
|
|
i = strlen (buffer);
|
|
if (i > 0 && buffer[i-1] == '\n') buffer[i-1] = '\0';
|
|
SID = buffer;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* if the sid file is open save current sid.
|
|
*/
|
|
int FBSmartHome::CloseSIDFile() {
|
|
if (fsidfile != NULL) {
|
|
fseek (fsidfile, 0, SEEK_SET);
|
|
fprintf (fsidfile, "%s", SID.c_str());
|
|
fclose(fsidfile);
|
|
fsidfile = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int FBSmartHome::XMLReadAttr(FBSmartHomeDevice *dev, std::string objPrefix, xmlDocPtr xmldoc, xmlAttrPtr xmlattr) {
|
|
char *txt = NULL;
|
|
|
|
while (xmlattr) {
|
|
if (dev->others.length() > 0) dev->others += "\t";
|
|
txt = (char*) xmlNodeListGetString(xmldoc, xmlattr->children, 1);
|
|
if (txt != NULL)
|
|
dev->others += objPrefix + "." + (std::string)(char*) xmlattr->name + "=" + txt;
|
|
else
|
|
dev->others += (std::string)(char*) xmlattr->name + "=";
|
|
|
|
xmlattr = xmlattr->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int FBSmartHome::XMLReadOBJ(FBSmartHomeDevice *dev, std::string objPrefix, xmlDocPtr xmldoc, xmlNodePtr xmlobj) {
|
|
std::string tmp = "";
|
|
char *txt = NULL;
|
|
|
|
while (xmlobj) {
|
|
if (dev->others.length() > 0) dev->others += "\t";
|
|
txt = (char*) xmlNodeListGetString(xmldoc, xmlobj->children, 1);
|
|
if (txt != NULL)
|
|
dev->others += objPrefix + "." + (std::string)(char*) xmlobj->name + "=" + txt;
|
|
else if (xmlobj->children) {
|
|
XMLReadAttr(dev, objPrefix+"."+(std::string)(char*)xmlobj->name, xmldoc, xmlobj->properties);
|
|
XMLReadOBJ(dev, objPrefix+"."+(std::string)(char*)xmlobj->name, xmldoc, xmlobj->children);
|
|
}
|
|
else
|
|
dev->others += (std::string)(char*) xmlobj->name + "=";
|
|
|
|
xmlobj = xmlobj->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int FBSmartHome::XMLReadAndAddDevice(std::list<FBSmartHomeDevice> *devlist, std::string defType,
|
|
xmlDocPtr xmldoc, xmlNodePtr xmlnode) {
|
|
xmlAttrPtr xmlattr;
|
|
xmlNodePtr child;
|
|
std::string tmp = "";
|
|
char *txt = NULL;
|
|
FBSmartHomeDevice fbdev;
|
|
|
|
//
|
|
// reset all fields
|
|
fbdev.others = "";
|
|
fbdev.id = "";
|
|
fbdev.name = "";
|
|
fbdev.type = defType;
|
|
|
|
//
|
|
// read attributes
|
|
xmlattr = xmlnode->properties;
|
|
while (xmlattr) {
|
|
if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"identifier"))
|
|
fbdev.id = (char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1);
|
|
else {
|
|
txt = (char*) xmlNodeListGetString(xmldoc, xmlattr->children, 1);
|
|
|
|
if (txt != NULL) fbdev.others += (std::string)(char*) xmlattr->name + "=" + txt + "\t";
|
|
else fbdev.others += (std::string)(char*) xmlattr->name + "=\t";
|
|
}
|
|
xmlattr = xmlattr->next;
|
|
}
|
|
|
|
//
|
|
// read subelements
|
|
child = xmlnode->children;
|
|
while (child) {
|
|
if (!xmlStrcmp(child->name, (const xmlChar *)"name"))
|
|
fbdev.name = (char *) xmlNodeListGetString(xmldoc, child->children, 1);
|
|
|
|
else if (!xmlStrcmp(child->name, (const xmlChar *)"button")) {
|
|
fbdev.type = "button";
|
|
XMLReadAndAddDevice(devlist, "button", xmldoc, child);
|
|
}
|
|
|
|
else if (!xmlStrcmp(child->name, (const xmlChar *)"hkr")) {
|
|
fbdev.type = (char*)child->name;
|
|
XMLReadOBJ(&fbdev, "hkr" , xmldoc, child->children);
|
|
}
|
|
|
|
else {
|
|
txt = (char*) xmlNodeListGetString(xmldoc, child->children, 1);
|
|
if (txt != NULL) {
|
|
fbdev.others += (std::string)(char*) child->name + "=" + txt + "\t";
|
|
} else {
|
|
if (child->children) {
|
|
XMLReadAttr(&fbdev, (std::string)(char*)child->name, xmldoc, child->properties);
|
|
XMLReadOBJ(&fbdev, (std::string)(char*)child->name, xmldoc, child->children);
|
|
}
|
|
else {
|
|
fbdev.others += (std::string)(char*) child->name + "=\t";
|
|
}
|
|
}
|
|
}
|
|
|
|
child = child->next;
|
|
}
|
|
devlist->push_back(fbdev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* retrieve the device list from the fritzbox
|
|
*/
|
|
std::list<FBSmartHomeDevice> *FBSmartHome::GetDevices() {
|
|
std::list<FBSmartHomeDevice> *devlist = NULL;
|
|
FBSmartHomeDevice smd;
|
|
xmlDocPtr xmldoc;
|
|
xmlNodePtr xmlnode;
|
|
|
|
int len;
|
|
devlist = new std::list<FBSmartHomeDevice>;
|
|
|
|
// retrieve data
|
|
len = tcp.WebGetFile(hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=getdevicelistinfos", inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return NULL;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"devicelist"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
|
|
//
|
|
// read each device details
|
|
//
|
|
while (xmlchild) {
|
|
if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"device"))
|
|
XMLReadAndAddDevice(devlist, "", xmldoc, xmlchild);
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
if (SID.compare("0000000000000000") == 0) {
|
|
hostname = "";
|
|
errno = ENOTCONN;
|
|
return NULL;
|
|
}
|
|
|
|
return devlist;
|
|
}
|
|
|
|
|
|
/*
|
|
* read data from device and fill out FBSmartHomeHZR structure
|
|
*/
|
|
int FBSmartHome::GetHKR(std::string ain, FBSmartHomeHKR *hkr) {
|
|
std::string s;
|
|
FBSmartHomeDevice smd;
|
|
xmlDocPtr xmldoc;
|
|
xmlNodePtr xmlnode;
|
|
xmlAttrPtr xmlattr;
|
|
int len, i;
|
|
|
|
if (hkr == NULL) return -1;
|
|
for (s = "", i = 0; i < (int)ain.length(); i++) {
|
|
if (ain[i] == ' ') s += "%20";
|
|
else s += ain[i];
|
|
}
|
|
|
|
//
|
|
// read device info
|
|
//
|
|
|
|
//
|
|
// retrieve data
|
|
len = tcp.WebGetFile(hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=getdeviceinfos&ain="+s, inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"device"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
|
|
xmlattr = xmlnode->properties;
|
|
while (xmlattr) {
|
|
if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"identifier"))
|
|
hkr->id = (char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1);
|
|
xmlattr = xmlattr->next;
|
|
}
|
|
while (xmlchild) {
|
|
|
|
// name
|
|
if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"name"))
|
|
hkr->name = (char *) xmlNodeListGetString(xmldoc, xmlchild->children, 1);
|
|
|
|
// temperatur
|
|
else if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"temperature")) {
|
|
xmlNodePtr xmlc = xmlchild->children;
|
|
while(xmlc) {
|
|
if (!xmlStrcmp(xmlc->name, (const xmlChar *)"celsius")) {
|
|
hkr->temp = (atof_check((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1))) / 10.0;
|
|
}
|
|
else if (!xmlStrcmp(xmlc->name, (const xmlChar *)"offset")) {
|
|
hkr->offset = atoi_check ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1), -999);
|
|
}
|
|
|
|
xmlc = xmlc->next;
|
|
}
|
|
}
|
|
|
|
// hkr
|
|
else if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"hkr")) {
|
|
xmlNodePtr xmlc = xmlchild->children;
|
|
while(xmlc) {
|
|
if (!xmlStrcmp(xmlc->name, (const xmlChar *)"tist")) {
|
|
hkr->temp_cur = atof_check ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1));
|
|
hkr->temp_cur = hkr->temp_cur / 2.0;
|
|
}
|
|
else if (!xmlStrcmp(xmlc->name, (const xmlChar *)"tsoll")) {
|
|
hkr->temp_set = atof_check ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1));
|
|
hkr->temp_set = hkr->temp_set / 2.0;
|
|
}
|
|
else if (!xmlStrcmp(xmlc->name, (const xmlChar *)"absenk")) {
|
|
hkr->temp_l = atof_check ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1));
|
|
hkr->temp_l = hkr->temp_l / 2.0;
|
|
}
|
|
else if (!xmlStrcmp(xmlc->name, (const xmlChar *)"komfort")) {
|
|
hkr->temp_h = atof_check ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1));
|
|
hkr->temp_h = hkr->temp_h / 2.0;
|
|
}
|
|
|
|
xmlc = xmlc->next;
|
|
}
|
|
}
|
|
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
//
|
|
//
|
|
//
|
|
// retrieve data
|
|
len = tcp.WebGetFile(hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=getbasicdevicestats&ain="+s, inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"devicestats"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
std::string txt;
|
|
float f;
|
|
char *t;
|
|
|
|
while (xmlchild) {
|
|
// temperatur
|
|
if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"temperature")) {
|
|
xmlNodePtr xmlc = xmlchild->children;
|
|
int count = 0;
|
|
|
|
while(xmlc) {
|
|
if (!xmlStrcmp(xmlc->name, (const xmlChar *)"stats")) {
|
|
xmlattr = xmlc->properties;
|
|
while (xmlattr) {
|
|
if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"count"))
|
|
count = atoi_check((char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1), -999);
|
|
else if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"grid"))
|
|
hkr-> statsgrid = atoi_check((char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1), -999);
|
|
xmlattr = xmlattr->next;
|
|
}
|
|
|
|
txt = ((char *) xmlNodeListGetString(xmldoc, xmlc->children, 1));
|
|
|
|
hkr->stats.clear();
|
|
t = (char*)txt.c_str();
|
|
for (int i = 0; t != NULL && i < count; i++) {
|
|
if (*t == ',') t++;
|
|
f = atoi_check (t, 0);
|
|
hkr->stats.push_back(f);
|
|
t = strchr(t, ',');
|
|
}
|
|
}
|
|
xmlc = xmlc->next;
|
|
}
|
|
}
|
|
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
xmlFreeDoc(xmldoc);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* switch device off = 0, on = 1 or toggle = 2
|
|
*/
|
|
int FBSmartHome::SimpleOnOff(std::string ain, int oot) {
|
|
std::string s;
|
|
int i, len;
|
|
|
|
if (ain.length() <= 0) return -1;
|
|
for (s = "", i = 0; i < (int)ain.length(); i++) {
|
|
if (ain[i] == ' ') s += "%20";
|
|
else s += ain[i];
|
|
}
|
|
|
|
//
|
|
// send switch on / off
|
|
len = tcp.WebGetFile(hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=setsimpleonoff&ain="+s+"&onoff="+to_string(oot), inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* set device level 0...255 (0-100%)
|
|
*/
|
|
int FBSmartHome::SetLevel(std::string ain, int level) {
|
|
std::string s;
|
|
int i, len;
|
|
|
|
if (ain.length() <= 0) return -1;
|
|
for (s = "", i = 0; i < (int)ain.length(); i++) {
|
|
if (ain[i] == ' ') s += "%20";
|
|
else s += ain[i];
|
|
}
|
|
|
|
//
|
|
// send switch on / off
|
|
len = tcp.WebGetFile(hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=setlevel&ain="+s+"&level="+to_string(level), inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
std::list<FBSmartHomeLightDefaults> *FBSmartHome::GetColorDefaults (std::string ain) {
|
|
std::list<FBSmartHomeLightDefaults> *lst = new std::list<FBSmartHomeLightDefaults>;
|
|
std::string cmd;
|
|
std::string s;
|
|
int i, len;
|
|
xmlDocPtr xmldoc;
|
|
xmlNodePtr xmlnode;
|
|
xmlAttrPtr xmlattr;
|
|
|
|
//
|
|
// convert space char to %20 to be used in URLs
|
|
//
|
|
if (ain.length() <= 0) return lst;
|
|
for (s = "", i = 0; i < (int)ain.length(); i++) {
|
|
if (ain[i] == ' ') s += "%20";
|
|
else s += ain[i];
|
|
}
|
|
|
|
cmd = hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=getcolordefaults&ain="+s;
|
|
|
|
//
|
|
// send switch on / off
|
|
len = tcp.WebGetFile(cmd, inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return lst;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
|
|
//
|
|
// convert inbuffer to list of values
|
|
//
|
|
XMLPrepare(inbuffer, len, &xmldoc, &xmlnode);
|
|
|
|
//
|
|
// parse for SID and Challange
|
|
while (xmlnode) {
|
|
if ((!xmlStrcmp(xmlnode->name, (const xmlChar *)"colordefaults"))){
|
|
xmlNodePtr xmlchild = xmlnode->xmlChildrenNode;
|
|
std::string txt;
|
|
|
|
while (xmlchild) {
|
|
// hsdefaults
|
|
if (!xmlStrcmp(xmlchild->name, (const xmlChar *)"hsdefaults")) {
|
|
xmlNodePtr xmlhs = xmlchild->children;
|
|
|
|
while(xmlhs) {
|
|
if (!xmlStrcmp(xmlhs->name, (const xmlChar *)"hs")) {
|
|
xmlNodePtr xmlc = xmlhs->children;
|
|
|
|
while (xmlc) {
|
|
if (!xmlStrcmp(xmlc->name, (const xmlChar *)"color")) {
|
|
xmlattr = xmlc->properties;
|
|
FBSmartHomeLightDefaults def = { -1, -1, -1 };
|
|
while (xmlattr) {
|
|
if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"hue"))
|
|
def.hue = atoi_check((char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1), 0);
|
|
else if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"sat"))
|
|
def.sat = atoi_check((char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1), 0);
|
|
else if (!xmlStrcmp(xmlattr->name, (const xmlChar *)"val"))
|
|
def.val = atoi_check((char *) xmlNodeListGetString(xmldoc, xmlattr->children, 1), 0);
|
|
xmlattr = xmlattr->next;
|
|
}
|
|
if (def.hue != -1) lst->push_back(def);
|
|
|
|
}
|
|
xmlc = xmlc->next;
|
|
}
|
|
}
|
|
xmlhs = xmlhs->next;
|
|
}
|
|
}
|
|
|
|
xmlchild = xmlchild->next;
|
|
}
|
|
|
|
}
|
|
xmlnode = xmlnode->next;
|
|
}
|
|
|
|
return lst;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
int FBSmartHome::SetColor(std::string ain, int hue, int sat, int duration) {
|
|
std::list<FBSmartHomeLightDefaults> *defcolors = NULL;
|
|
std::list<FBSmartHomeLightDefaults>::iterator iter;
|
|
std::string s;
|
|
std::string cmd;
|
|
int i, len;
|
|
float delta;
|
|
struct {
|
|
float delta;
|
|
int hue;
|
|
int sat;
|
|
int val;
|
|
} selected_color;
|
|
|
|
//
|
|
// convert space char to %20 to be used in URLs
|
|
//
|
|
if (ain.length() <= 0) return -1;
|
|
for (s = "", i = 0; i < (int)ain.length(); i++) {
|
|
if (ain[i] == ' ') s += "%20";
|
|
else s += ain[i];
|
|
}
|
|
|
|
//
|
|
// need to read defaults and round up to the next closest parameters
|
|
//
|
|
defcolors = GetColorDefaults(ain);
|
|
iter = defcolors->begin();
|
|
if (iter != defcolors->end()) {
|
|
selected_color.hue = iter->hue;
|
|
selected_color.sat = iter->sat;
|
|
selected_color.val = iter->val;
|
|
selected_color.delta = (iter->hue - hue) * (iter->hue - hue)
|
|
+ (iter->sat - sat) * (iter->hue - sat);
|
|
|
|
for (iter++; iter != defcolors->end(); iter++) {
|
|
delta = (iter->hue - hue) * (iter->hue - hue)
|
|
+ (iter->sat - sat) * (iter->hue - sat);
|
|
if (delta < selected_color.delta) {
|
|
selected_color.hue = iter->hue;
|
|
selected_color.sat = iter->sat;
|
|
selected_color.val = iter->val;
|
|
selected_color.delta = delta;
|
|
}
|
|
}
|
|
|
|
cmd = hostname+"/webservices/homeautoswitch.lua?sid="+SID+"&switchcmd=setcolor&ain="+s;
|
|
cmd += "&hue="+to_string(selected_color.hue)+"&saturation="+to_string(selected_color.sat)+"&duration="+to_string(duration);
|
|
|
|
printf ("%s:%d SetColor ain:'%s' hue,sat %d,%d selected hue,sat: %d,%d duration:%d\n", __FILE__, __LINE__, ain.c_str(),
|
|
hue, sat, selected_color.hue, selected_color.sat, duration);
|
|
|
|
//
|
|
// send switch on / off
|
|
len = tcp.WebGetFile(cmd, inbuffer, FB_BUFFER, NULL);
|
|
if (len > FB_BUFFER) len = FB_BUFFER;
|
|
else if (len < 0) {
|
|
fprintf (stderr, "%s:%d Error getting challenge from Fritzbox\n", __FILE__, __LINE__);
|
|
errno = EAI_FAIL;
|
|
return -1;
|
|
}
|
|
inbuffer[len] = '\0';
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|