// MQTT PUBLISH implementation for LOXONE // Version 0.1 ... 2017-11-04 ... kianusch@gmail.com // Version 0.2 ... 2017-11-08 ... kianusch@gmail.com // Version 0.3 ... 2017-11-14 ... kianusch@gmail.com #define CONNECT 0x10 #define CONNACK 0x20 #define PUBLISH 0x30 #define PINGREQ 0xC0 #define PINGRESP 0xD0 #define DISCONNECT 0xE0 #define KEEPALIVE 30 // #define CLIENTID "iobroker" #define DEVICE "/dev/tcp/192.168.x.x/1883" #define USERNAME "user" #define PASSWORD "passwd" char* topic[13]; topic[0]="esp01/gpio/12"; topic[1]="esp02/gpio/12"; topic[2]="esp03/gpio/12"; topic[3]="esp04/gpio/12"; topic[4]="esp05/pwm/12"; topic[5]=""; topic[6]=""; topic[7]=""; topic[8]=""; topic[9]=""; topic[10]=""; topic[11]=""; topic[12]=""; char conHeader[2] = {CONNECT, 0}; char conMessage[10] = {0, 4, 'M', 'Q', 'T', 'T', 4, 2, 0, KEEPALIVE}; char conPayload[128]; char disCon[2] = {DISCONNECT, 0}; char pingReq[2] = {PINGREQ, 0}; char pubHeader[2] = {PUBLISH, 0}; int nEvents; int input; char inputStr[8]; STREAM* stream = NULL; int keepalive; void tostring(char *str, int num) { int i, rem, len = 0, n; n = num; while (n != 0) { len++; n /= 10; } for (i = 0; i < len; i++) { rem = num % 10; num = num / 10; str[len - (i + 1)] = rem + '0'; } str[len] = '\0'; } void setConMessage() { char *ppayload; conMessage[7] |= 0x02; int len; int tmpLen; ppayload=conPayload; // set Client Identifier to blank *(ppayload++)=0; *(ppayload++)=0; len=2; if (USERNAME != NULL) { conMessage[7] |= 0x80; tmpLen=strlen(USERNAME); *(ppayload++)=0; *(ppayload++)=tmpLen; strcpy(ppayload, USERNAME); ppayload+=tmpLen; len+=(tmpLen+2); } if (PASSWORD != NULL) { conMessage[7] |= 0x40; tmpLen=strlen(PASSWORD); *(ppayload++)=0; *(ppayload++)=tmpLen; strcpy(ppayload, PASSWORD); ppayload+=tmpLen; len+=(tmpLen+2); } conHeader[1]=10+len; } STREAM* connect() { STREAM* mystream; char response[2]; int len; mystream = stream_create(DEVICE,0,0); if (mystream != NULL) { stream_write(mystream,conHeader,2); stream_write(mystream,conMessage,10); len=conHeader[1]-10; stream_write(mystream,conPayload,len); stream_flush(mystream); len=stream_read(mystream,response,2,1000); if (len==2 && response[0] == CONNACK && response[1] == 2) { stream_read(mystream,response,2,1000); if (response[0] == 0 && response[1] == 0) { return mystream; } printf("MQTT: ACK failed. [Session Present: %02x / Code: %02x]", response[0], response[1]); } else { printf("MQTT: ACK failed. [len: %d / code: %02x]", len, response[0]); } stream_write(mystream,disConHeader,2); stream_flush(mystream); stream_close(mystream); } return NULL; } void publish(STREAM* stream, char* topic, char* message) { char payload[128]; char payloadLen[2]; strcpy(payload,topic); strcat(payload,message); pubHeader[1]=strlen(payload)+2; stream_write(stream,pubHeader,2); payloadLen[0]=0; payloadLen[1]=strlen(topic); stream_write(stream,payloadLen,2); stream_write(stream,payload,strlen(payload)); stream_flush(stream); } int ping(STREAM* stream) { int len; stream_write(stream,pingReq,2); stream_flush(stream); char response[2]; len=stream_read(stream,response,2,1000); if (len==2 && response[0] == PINGRESP && response[1] == 0) { return 1; } else { printf("MQTT: ACK failed. [len: %d / code: %02x]", len, response[0]); stream_close(stream); return 0; } } /* void disconnect(STREAM* stream) { stream_write(stream,disConHeader,2); stream_flush(stream); stream_close(stream); } */ setConMessage(); // Main loop while(TRUE) { if (stream == NULL) { stream = connect(); keepalive=KEEPALIVE; } if (stream != NULL) { nEvents = getinputevent(); if (nEvents & 0xFFF8) { for (input=0;input<13;input++) { if (nEvents & (0x8 << input)) { float inMsg = getinput(input); tostring(inputStr,(int)inMsg); publish(stream,topic[input],inputStr); } } sleep(100); keepalive=KEEPALIVE; } else { keepalive--; if (! keepalive) { keepalive=KEEPALIVE; if (!ping(stream)) { stream = NULL; } } sleep (500); } } else { sleep (500); } }