@ -9,7 +9,6 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
# if HOMEASSISTANT_SUPPORT
# include <ArduinoJson.h>
# include <queue>
bool _haEnabled = false ;
bool _haSendFlag = false ;
@ -18,7 +17,29 @@ bool _haSendFlag = false;
// UTILS
// -----------------------------------------------------------------------------
String _haFixName ( String name ) {
// per yaml 1.1 spec, following scalars are converted to bool. we want the string, so quoting the output
// y|Y|yes|Yes|YES|n|N|no|No|NO |true|True|TRUE|false|False|FALSE |on|On|ON|off|Off|OFF
String _haFixPayload ( const String & value ) {
if ( value . equalsIgnoreCase ( " y " )
| | value . equalsIgnoreCase ( " n " )
| | value . equalsIgnoreCase ( " yes " )
| | value . equalsIgnoreCase ( " no " )
| | value . equalsIgnoreCase ( " true " )
| | value . equalsIgnoreCase ( " false " )
| | value . equalsIgnoreCase ( " on " )
| | value . equalsIgnoreCase ( " off " )
) {
String temp ;
temp . reserve ( value . length ( ) + 2 ) ;
temp = " \" " ;
temp + = value ;
temp + = " \" " ;
return temp ;
}
return value ;
}
String & _haFixName ( String & name ) {
for ( unsigned char i = 0 ; i < name . length ( ) ; i + + ) {
if ( ! isalnum ( name . charAt ( i ) ) ) name . setCharAt ( i , ' _ ' ) ;
}
@ -74,7 +95,6 @@ void _haSendMagnitude(unsigned char i, JsonObject& config) {
unsigned char type = magnitudeType ( i ) ;
config [ " name " ] = _haFixName ( getSetting ( " hostname " ) + String ( " " ) + magnitudeTopic ( type ) ) ;
config . set ( " platform " , " mqtt " ) ;
config [ " state_topic " ] = mqttTopic ( magnitudeTopicIndex ( i ) . c_str ( ) , false ) ;
config [ " unit_of_measurement " ] = magnitudeUnits ( type ) ;
}
@ -102,7 +122,7 @@ void _haSendMagnitudes(ha_config_t& config) {
}
mqttSend ( MQTT_TOPIC_STATUS , MQTT_STATUS_ONLINE , true ) ;
mqttSendStatus ( ) ;
}
@ -120,16 +140,15 @@ void _haSendSwitch(unsigned char i, JsonObject& config) {
}
config . set ( " name " , _haFixName ( name ) ) ;
config . set ( " platform " , " mqtt " ) ;
if ( relayCount ( ) ) {
config [ " state_topic " ] = mqttTopic ( MQTT_TOPIC_RELAY , i , false ) ;
config [ " command_topic " ] = mqttTopic ( MQTT_TOPIC_RELAY , i , true ) ;
config [ " payload_on " ] = String ( HOMEASSISTANT_PAYLOAD_ON ) ;
config [ " payload_off " ] = String ( HOMEASSISTANT_PAYLOAD_OFF ) ;
config [ " payload_on " ] = relayPayload ( true ) ;
config [ " payload_off " ] = relayPayload ( false ) ;
config [ " availability_topic " ] = mqttTopic ( MQTT_TOPIC_STATUS , false ) ;
config [ " payload_available " ] = String ( HOMEASSISTANT_PAYLOAD_AVAILABLE ) ;
config [ " payload_not_available " ] = String ( HOMEASSISTANT_PAYLOAD_NOT_AVAILABLE ) ;
config [ " payload_available " ] = mqttPayloadStatus ( true ) ;
config [ " payload_not_available " ] = mqttPayloadStatus ( false ) ;
}
# if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
@ -178,109 +197,93 @@ void _haSendSwitches(ha_config_t& config) {
}
mqttSendRaw ( topic . c_str ( ) , output . c_str ( ) ) ;
mqttSend ( MQTT_TOPIC_STATUS , MQTT_STATUS_ONLINE , true ) ;
}
mqttSendStatus ( ) ;
}
// -----------------------------------------------------------------------------
void _haDumpConfig ( std : : function < void ( String & ) > printer , bool wrapJson = false ) {
constexpr const size_t HA_YAML_BUFFER_SIZE = 1024 ;
constexpr const size_t BUFFER_SIZE = 1024 ;
void _haSwitchYaml ( unsigned char index , JsonObject & root ) {
String output ;
output . reserve ( BUFFER_SIZE + 64 ) ;
DynamicJsonBuffer jsonBuffer ( BUFFER_SIZE ) ;
output . reserve ( HA_YAML_BUFFER_SIZE ) ;
for ( unsigned char i = 0 ; i < relayCount ( ) ; i + + ) {
JsonObject & config = root . createNestedObject ( " config " ) ;
_haSendSwitch ( index , config ) ;
JsonObject & config = jsonBuffer . createObject ( ) ;
_haSendSwitch ( i , config ) ;
if ( index = = 0 ) output + = " \n \n " + switchType + " : " ;
output + = " \n " ;
bool first = true ;
if ( wrapJson ) {
output + = " { \" haConfig \" : \" " ;
for ( auto kv : config ) {
if ( first ) {
output + = " - " ;
first = false ;
} else {
output + = " " ;
}
output + = " \n \n " + switchType + " : \n " ;
bool first = true ;
for ( auto kv : config ) {
if ( first ) {
output + = " - " ;
first = false ;
} else {
output + = " " ;
}
output + = kv . key ;
output + = " : " ;
output + = kv . key ;
output + = " : " ;
if ( strncmp ( kv . key , " payload_ " , strlen ( " payload_ " ) ) = = 0 ) {
output + = _haFixPayload ( kv . value . as < String > ( ) ) ;
} else {
output + = kv . value . as < String > ( ) ;
output + = " \n " ;
}
output + = " " ;
if ( wrapJson ) {
output + = " \" } " ;
}
jsonBuffer . clear ( ) ;
printer ( output ) ;
output = " " ;
output + = " \n " ;
}
output + = " " ;
# if SENSOR_SUPPORT
for ( unsigned char i = 0 ; i < magnitudeCount ( ) ; i + + ) {
root . remove ( " config " ) ;
root [ " haConfig " ] = output ;
}
JsonObject & config = jsonBuffer . createObject ( ) ;
_haSendMagnitude ( i , config ) ;
# if SENSOR_SUPPORT
if ( wrapJson ) {
output + = " { \" haConfig \" : \" " ;
}
void _haSensorYaml ( unsigned char index , JsonObject & root ) {
output + = " \n \n sensor: \n " ;
bool first = true ;
for ( auto kv : config ) {
if ( first ) {
output + = " - " ;
first = false ;
} else {
output + = " " ;
}
String value = kv . value . as < String > ( ) ;
value . replace ( " % " , " '%' " ) ;
output + = kv . key ;
output + = " : " ;
output + = value ;
output + = " \n " ;
}
output + = " " ;
String output ;
output . reserve ( HA_YAML_BUFFER_SIZE ) ;
if ( wrapJson ) {
output + = " \" } " ;
}
JsonObject & config = root . createNestedObject ( " config " ) ;
_haSendMagnitude ( index , config ) ;
jsonBuffer . clear ( ) ;
printer ( output ) ;
output = " " ;
if ( index = = 0 ) output + = " \n \n sensor: " ;
output + = " \n " ;
bool first = true ;
for ( auto kv : config ) {
if ( first ) {
output + = " - " ;
first = false ;
} else {
output + = " " ;
}
String value = kv . value . as < String > ( ) ;
value . replace ( " % " , " '%' " ) ;
output + = kv . key ;
output + = " : " ;
output + = value ;
output + = " \n " ;
}
output + = " " ;
root . remove ( " config " ) ;
root [ " haConfig " ] = output ;
# endif
}
# endif // SENSOR_SUPPORT
void _haGetDeviceConfig ( JsonObject & config ) {
String identifier = getIdentifier ( ) ;
config . createNestedArray ( " identifiers " ) . add ( identifier ) ;
config . createNestedArray ( " identifiers " ) . add ( getIdentifier ( ) ) ;
config [ " name " ] = getSetting ( " desc " , getSetting ( " hostname " ) ) ;
config [ " manufacturer " ] = String ( MANUFACTURER ) ;
config [ " model " ] = String ( DEVICE ) ;
config [ " sw_version " ] = String ( APP_NAME ) + " " + String ( APP_VERSION ) + " ( " + getCoreVersion ( ) + " ) " ;
config [ " manufacturer " ] = MANUFACTURER ;
config [ " model " ] = DEVICE ;
config [ " sw_version " ] = String ( APP_NAME ) + " " + APP_VERSION + " ( " + getCoreVersion ( ) + " ) " ;
}
void _haSend ( ) {
@ -315,8 +318,6 @@ void _haConfigure() {
# if WEB_SUPPORT
std : : queue < uint32_t > _ha_send_config ;
bool _haWebSocketOnKeyCheck ( const char * key , JsonVariant & value ) {
return ( strncmp ( key , " ha " , 2 ) = = 0 ) ;
}
@ -332,20 +333,53 @@ void _haWebSocketOnConnected(JsonObject& root) {
void _haWebSocketOnAction ( uint32_t client_id , const char * action , JsonObject & data ) {
if ( strcmp ( action , " haconfig " ) = = 0 ) {
_ha_send_config . push ( client_id ) ;
ws_on_send_callback_list_t callbacks ;
# if SENSOR_SUPPORT
callbacks . reserve ( magnitudeCount ( ) + relayCount ( ) ) ;
# else
callbacks . reserve ( relayCount ( ) ) ;
# endif // SENSOR_SUPPORT
{
for ( unsigned char idx = 0 ; idx < relayCount ( ) ; + + idx ) {
callbacks . push_back ( [ idx ] ( JsonObject & root ) {
_haSwitchYaml ( idx , root ) ;
} ) ;
}
}
# if SENSOR_SUPPORT
{
for ( unsigned char idx = 0 ; idx < magnitudeCount ( ) ; + + idx ) {
callbacks . push_back ( [ idx ] ( JsonObject & root ) {
_haSensorYaml ( idx , root ) ;
} ) ;
}
}
# endif // SENSOR_SUPPORT
if ( callbacks . size ( ) ) wsPostSequence ( client_id , std : : move ( callbacks ) ) ;
}
}
# endif
# endif // WEB_SUPPORT
# if TERMINAL_SUPPORT
void _haInitCommands ( ) {
terminalRegisterCommand ( F ( " HA.CONFIG " ) , [ ] ( Embedis * e ) {
_haDumpConfig ( [ ] ( String & data ) {
DEBUG_MSG ( data . c_str ( ) ) ;
} ) ;
for ( unsigned char idx = 0 ; idx < relayCount ( ) ; + + idx ) {
DynamicJsonBuffer jsonBuffer ( 1024 ) ;
JsonObject & root = jsonBuffer . createObject ( ) ;
_haSwitchYaml ( idx , root ) ;
DEBUG_MSG ( root [ " haConfig " ] . as < String > ( ) . c_str ( ) ) ;
}
# if SENSOR_SUPPORT
for ( unsigned char idx = 0 ; idx < magnitudeCount ( ) ; + + idx ) {
DynamicJsonBuffer jsonBuffer ( 1024 ) ;
JsonObject & root = jsonBuffer . createObject ( ) ;
_haSensorYaml ( idx , root ) ;
DEBUG_MSG ( root [ " haConfig " ] . as < String > ( ) . c_str ( ) ) ;
}
# endif // SENSOR_SUPPORT
DEBUG_MSG ( " \n " ) ;
terminalOK ( ) ;
} ) ;
@ -374,23 +408,6 @@ void _haInitCommands() {
// -----------------------------------------------------------------------------
# if WEB_SUPPORT
void _haLoop ( ) {
if ( _ha_send_config . empty ( ) ) return ;
uint32_t client_id = _ha_send_config . front ( ) ;
_ha_send_config . pop ( ) ;
if ( ! wsConnected ( client_id ) ) return ;
// TODO check wsConnected after each "printer" call?
_haDumpConfig ( [ client_id ] ( String & output ) {
wsSend ( client_id , output . c_str ( ) ) ;
yield ( ) ;
} , true ) ;
}
# endif
void haSetup ( ) {
_haConfigure ( ) ;
@ -401,7 +418,6 @@ void haSetup() {
. onConnected ( _haWebSocketOnConnected )
. onAction ( _haWebSocketOnAction )
. onKeyCheck ( _haWebSocketOnKeyCheck ) ;
espurnaRegisterLoop ( _haLoop ) ;
# endif
# if TERMINAL_SUPPORT