2018-09-28 23:53:51 +02:00
/*
* MQTT communication protocol for home automation
*/
2018-09-30 20:24:57 +02:00
void parseMQTTBriPayload ( char * payload )
{
2019-04-14 19:31:25 +02:00
if ( strstr ( payload , " ON " ) | | strstr ( payload , " on " ) | | strstr ( payload , " true " ) ) { bri = briLast ; colorUpdated ( 1 ) ; }
2019-03-27 21:31:59 +01:00
else if ( strstr ( payload , " T " ) | | strstr ( payload , " t " ) ) { toggleOnOff ( ) ; colorUpdated ( 1 ) ; }
2018-09-30 20:24:57 +02:00
else {
uint8_t in = strtoul ( payload , NULL , 10 ) ;
if ( in = = 0 & & bri > 0 ) briLast = bri ;
bri = in ;
2018-09-28 23:53:51 +02:00
colorUpdated ( 1 ) ;
}
2018-09-30 20:24:57 +02:00
}
2018-11-09 17:00:36 +01:00
2019-02-17 19:21:09 +01:00
void onMqttConnect ( bool sessionPresent )
{
//(re)subscribe to required topics
char subuf [ 38 ] ;
strcpy ( subuf , mqttDeviceTopic ) ;
2019-08-17 12:27:06 +02:00
2019-02-17 19:21:09 +01:00
if ( mqttDeviceTopic [ 0 ] ! = 0 )
{
strcpy ( subuf , mqttDeviceTopic ) ;
mqtt - > subscribe ( subuf , 0 ) ;
strcat ( subuf , " /col " ) ;
mqtt - > subscribe ( subuf , 0 ) ;
strcpy ( subuf , mqttDeviceTopic ) ;
strcat ( subuf , " /api " ) ;
mqtt - > subscribe ( subuf , 0 ) ;
}
if ( mqttGroupTopic [ 0 ] ! = 0 )
{
strcpy ( subuf , mqttGroupTopic ) ;
mqtt - > subscribe ( subuf , 0 ) ;
strcat ( subuf , " /col " ) ;
mqtt - > subscribe ( subuf , 0 ) ;
strcpy ( subuf , mqttGroupTopic ) ;
strcat ( subuf , " /api " ) ;
mqtt - > subscribe ( subuf , 0 ) ;
}
2019-03-18 17:23:39 +01:00
2019-10-20 17:38:25 +02:00
doSendHADiscovery = true ;
2019-10-25 00:14:58 +02:00
doPublishMqtt = true ;
2019-10-18 23:47:11 +02:00
DEBUG_PRINTLN ( " MQTT ready " ) ;
2019-02-17 19:21:09 +01:00
}
void onMqttMessage ( char * topic , char * payload , AsyncMqttClientMessageProperties properties , size_t len , size_t index , size_t total ) {
2018-09-30 20:24:57 +02:00
2019-10-20 17:38:25 +02:00
DEBUG_PRINT ( " MQTT msg: " ) ;
2018-09-30 20:24:57 +02:00
DEBUG_PRINTLN ( topic ) ;
2019-02-17 19:21:09 +01:00
DEBUG_PRINTLN ( payload ) ;
2018-09-30 20:24:57 +02:00
//no need to check the topic because we only get topics we are subscribed to
if ( strstr ( topic , " /col " ) )
2018-09-28 23:53:51 +02:00
{
2019-02-05 21:53:39 +01:00
colorFromDecOrHexString ( col , ( char * ) payload ) ;
2018-09-28 23:53:51 +02:00
colorUpdated ( 1 ) ;
2018-09-30 20:24:57 +02:00
} else if ( strstr ( topic , " /api " ) )
2018-09-28 23:53:51 +02:00
{
2018-10-04 16:50:12 +02:00
String apireq = " win& " ;
2018-10-04 18:17:01 +02:00
apireq + = ( char * ) payload ;
2019-02-16 00:21:22 +01:00
handleSet ( nullptr , apireq ) ;
2019-02-17 19:21:09 +01:00
} else parseMQTTBriPayload ( payload ) ;
2018-09-28 23:53:51 +02:00
}
2018-11-09 17:00:36 +01:00
2019-02-17 19:21:09 +01:00
void publishMqtt ( )
2018-09-28 23:53:51 +02:00
{
2019-10-20 17:38:25 +02:00
doPublishMqtt = false ;
2019-10-18 23:47:11 +02:00
if ( mqtt = = nullptr | | ! mqtt - > connected ( ) ) return ;
2018-09-30 20:24:57 +02:00
DEBUG_PRINTLN ( " Publish MQTT " ) ;
2018-09-28 23:53:51 +02:00
2018-10-04 16:50:12 +02:00
char s [ 10 ] ;
char subuf [ 38 ] ;
2019-08-17 12:27:06 +02:00
2018-10-04 16:50:12 +02:00
sprintf ( s , " %ld " , bri ) ;
strcpy ( subuf , mqttDeviceTopic ) ;
strcat ( subuf , " /g " ) ;
2019-02-17 19:21:09 +01:00
mqtt - > publish ( subuf , 0 , true , s ) ;
2018-10-04 16:50:12 +02:00
2019-04-15 20:43:32 +02:00
sprintf ( s , " #%06X " , col [ 3 ] * 16777216 + col [ 0 ] * 65536 + col [ 1 ] * 256 + col [ 2 ] ) ;
2018-10-04 16:50:12 +02:00
strcpy ( subuf , mqttDeviceTopic ) ;
strcat ( subuf , " /c " ) ;
2019-02-17 19:21:09 +01:00
mqtt - > publish ( subuf , 0 , true , s ) ;
2018-10-04 16:50:12 +02:00
2019-03-16 02:09:37 +01:00
char apires [ 1024 ] ;
XML_response ( nullptr , false , apires ) ;
2018-10-04 16:50:12 +02:00
strcpy ( subuf , mqttDeviceTopic ) ;
strcat ( subuf , " /v " ) ;
2019-03-16 02:09:37 +01:00
mqtt - > publish ( subuf , 0 , true , apires ) ;
2018-09-28 23:53:51 +02:00
}
2019-03-24 00:49:26 +01:00
const char HA_static_JSON [ ] PROGMEM = R " =====(, " bri_val_tpl " : " { { value } } " , " rgb_cmd_tpl " : " { { ' # % 02 x % 02 x % 02 x ' | format ( red , green , blue ) } } " , " rgb_val_tpl " : " { { value [ 1 : 3 ] | int ( base = 16 ) } } , { { value [ 3 : 5 ] | int ( base = 16 ) } } , { { value [ 5 : 7 ] | int ( base = 16 ) } } " , " qos " :0, " opt " :true, " pl_on " : " ON " , " pl_off " : " OFF " , " fx_val_tpl " : " { { value } } " , " fx_list " :[)===== " ;
2019-10-25 00:14:58 +02:00
char buffer [ 2400 ] ; //TODO: this is a TERRIBLE waste of precious memory, local var leads to exception though. Maybe dynamic allocation, but it is unclear when to free
2019-06-21 23:12:58 +02:00
void sendHADiscoveryMQTT ( )
{
2019-08-17 12:27:06 +02:00
2019-05-21 18:50:56 +02:00
# if ARDUINO_ARCH_ESP32 || LEDPIN != 3
2019-03-18 17:23:39 +01:00
/*
2019-10-25 15:32:09 +02:00
YYYY is device topic
2019-03-18 17:23:39 +01:00
XXXX is device name
Send out HA MQTT Discovery message on MQTT connect ( ~ 2.4 kB ) :
{
" name " : " XXXX " ,
" stat_t " : " YYYY/c " ,
" cmd_t " : " YYYY " ,
" rgb_stat_t " : " YYYY/c " ,
" rgb_cmd_t " : " YYYY/col " ,
" bri_cmd_t " : " YYYY " ,
" bri_stat_t " : " YYYY/g " ,
" bri_val_tpl " : " {{value}} " ,
" rgb_cmd_tpl " : " {{'#%02x%02x%02x' | format(red, green, blue)}} " ,
" rgb_val_tpl " : " {{value[1:3]|int(base=16)}},{{value[3:5]|int(base=16)}},{{value[5:7]|int(base=16)}} " ,
" qos " : 0 ,
" opt " : true ,
" pl_on " : " ON " ,
" pl_off " : " OFF " ,
" fx_cmd_t " : " YYYY/api " ,
" fx_stat_t " : " YYYY/api " ,
" fx_val_tpl " : " {{value}} " ,
" fx_list " : [
2019-03-24 18:28:36 +01:00
" [FX=00] Solid " ,
2019-08-17 12:27:06 +02:00
" [FX=01] Blink " ,
2019-03-24 18:28:36 +01:00
" [FX=02] ... " ,
" [FX=79] Ripple "
2019-03-18 17:23:39 +01:00
]
}
*/
2019-10-20 17:38:25 +02:00
doSendHADiscovery = false ;
if ( mqtt = = nullptr | | ! mqtt - > connected ( ) ) return ;
2019-10-25 00:14:58 +02:00
char bufc [ 36 ] , bufcol [ 38 ] , bufg [ 36 ] , bufapi [ 38 ] ;
2019-03-18 17:23:39 +01:00
strcpy ( bufc , mqttDeviceTopic ) ;
strcpy ( bufcol , mqttDeviceTopic ) ;
strcpy ( bufg , mqttDeviceTopic ) ;
strcpy ( bufapi , mqttDeviceTopic ) ;
strcat ( bufc , " /c " ) ;
strcat ( bufcol , " /col " ) ;
strcat ( bufg , " /g " ) ;
strcat ( bufapi , " /api " ) ;
2019-06-21 23:12:58 +02:00
StaticJsonDocument < JSON_OBJECT_SIZE ( 9 ) + 512 > root ;
2019-03-18 17:23:39 +01:00
root [ " name " ] = serverDescription ;
root [ " stat_t " ] = bufc ;
root [ " cmd_t " ] = mqttDeviceTopic ;
root [ " rgb_stat_t " ] = bufc ;
root [ " rgb_cmd_t " ] = bufcol ;
root [ " bri_cmd_t " ] = mqttDeviceTopic ;
root [ " bri_stat_t " ] = bufg ;
root [ " fx_cmd_t " ] = bufapi ;
root [ " fx_stat_t " ] = bufapi ;
2019-03-24 00:49:26 +01:00
2019-06-21 23:12:58 +02:00
size_t jlen = measureJson ( root ) ;
2019-10-20 17:38:25 +02:00
//DEBUG_PRINTLN(jlen);
2019-06-21 23:12:58 +02:00
serializeJson ( root , buffer , jlen ) ;
2019-03-18 17:23:39 +01:00
2019-03-24 00:49:26 +01:00
//add values which don't change
strcpy_P ( buffer + jlen - 1 , HA_static_JSON ) ;
olen = 0 ;
obuf = buffer + jlen - 1 + strlen_P ( HA_static_JSON ) ;
//add fx_list
uint16_t jmnlen = strlen_P ( JSON_mode_names ) ;
uint16_t nameStart = 0 , nameEnd = 0 ;
int i = 0 ;
bool isNameStart = true ;
for ( uint16_t j = 0 ; j < jmnlen ; j + + )
{
if ( pgm_read_byte ( JSON_mode_names + j ) = = ' \" ' | | j = = jmnlen - 1 )
{
2019-08-17 12:27:06 +02:00
if ( isNameStart )
2019-03-24 00:49:26 +01:00
{
nameStart = j + 1 ;
}
2019-08-17 12:27:06 +02:00
else
2019-03-24 00:49:26 +01:00
{
nameEnd = j ;
char mdnfx [ 64 ] , mdn [ 56 ] ;
uint16_t namelen = nameEnd - nameStart ;
strncpy_P ( mdn , JSON_mode_names + nameStart , namelen ) ;
mdn [ namelen ] = 0 ;
snprintf ( mdnfx , 64 , " \" [FX=%02d] %s \" , " , i , mdn ) ;
oappend ( mdnfx ) ;
2019-10-20 17:38:25 +02:00
//DEBUG_PRINTLN(mdnfx);
2019-03-24 00:49:26 +01:00
i + + ;
}
isNameStart = ! isNameStart ;
2019-08-17 12:27:06 +02:00
}
2019-03-24 00:49:26 +01:00
}
2019-03-24 18:28:36 +01:00
olen - - ;
oappend ( " ]} " ) ;
2019-03-24 00:49:26 +01:00
2019-03-18 17:23:39 +01:00
DEBUG_PRINT ( " HA Discovery Sending >> " ) ;
DEBUG_PRINTLN ( buffer ) ;
2019-06-21 23:12:58 +02:00
char pubt [ 25 + 12 + 8 ] ;
2019-10-18 23:47:11 +02:00
strcpy ( pubt , " homeassistant/light/ " ) ;
strcat ( pubt , mqttClientID ) ;
2019-03-18 17:23:39 +01:00
strcat ( pubt , " /config " ) ;
2019-10-25 15:32:09 +02:00
bool success = mqtt - > publish ( pubt , 0 , true , buffer ) ;
DEBUG_PRINTLN ( success ) ;
2019-05-21 18:50:56 +02:00
# endif
2019-03-18 17:23:39 +01:00
}
2018-11-09 17:00:36 +01:00
2019-02-17 19:21:09 +01:00
bool initMqtt ( )
2018-09-28 23:53:51 +02:00
{
2019-10-18 23:47:11 +02:00
lastMqttReconnectAttempt = millis ( ) ;
2019-10-18 14:06:07 +02:00
if ( mqttServer [ 0 ] = = 0 | | ! WLED_CONNECTED ) return false ;
2019-10-20 12:48:29 +02:00
if ( mqtt = = nullptr ) {
mqtt = new AsyncMqttClient ( ) ;
mqtt - > onMessage ( onMqttMessage ) ;
mqtt - > onConnect ( onMqttConnect ) ;
}
2019-05-21 18:50:56 +02:00
if ( mqtt - > connected ( ) ) return true ;
2019-08-17 12:27:06 +02:00
2019-10-18 23:47:11 +02:00
DEBUG_PRINTLN ( " Reconnecting MQTT " ) ;
2018-09-28 23:53:51 +02:00
IPAddress mqttIP ;
if ( mqttIP . fromString ( mqttServer ) ) //see if server is IP or domain
{
2019-08-18 18:14:17 +02:00
mqtt - > setServer ( mqttIP , mqttPort ) ;
2018-09-28 23:53:51 +02:00
} else {
2019-08-18 18:14:17 +02:00
mqtt - > setServer ( mqttServer , mqttPort ) ;
2018-09-28 23:53:51 +02:00
}
2019-08-17 12:27:06 +02:00
mqtt - > setClientId ( mqttClientID ) ;
2019-10-18 23:47:11 +02:00
if ( mqttUser [ 0 ] & & mqttPass [ 0 ] ) mqtt - > setCredentials ( mqttUser , mqttPass ) ;
2019-02-17 19:21:09 +01:00
mqtt - > connect ( ) ;
2018-09-28 23:53:51 +02:00
return true ;
}