From cd54372588342d949e13f1800a7bad9532a38cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Fri, 26 Jan 2018 11:24:36 +0100 Subject: [PATCH] HA auto-discover for multi-relay boards and sensors --- code/espurna/homeassitant.ino | 106 +++++++++++++++++++++++++++------- code/espurna/sensor.ino | 78 ++++++++++++++----------- 2 files changed, 130 insertions(+), 54 deletions(-) diff --git a/code/espurna/homeassitant.ino b/code/espurna/homeassitant.ino index 6028f3c3..e2117f29 100644 --- a/code/espurna/homeassitant.ino +++ b/code/espurna/homeassitant.ino @@ -20,15 +20,47 @@ void _haWebSocketOnSend(JsonObject& root) { root["haPrefix"] = getSetting("haPrefix", HOMEASSISTANT_PREFIX); } -void _haSend() { +#if SENSOR_SUPPORT - // Pending message to send? - if (!_haSendFlag) return; +void _haSendMagnitude(unsigned char i) { - // Are we connected? - if (!mqttConnected()) return; + String output; - DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n")); + if (_haEnabled) { + + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + + unsigned char type = magnitudeType(i); + + root["device_class"] = "sensor"; + root["name"] = getSetting("hostname") + String(" ") + magnitudeTopic(type); + root["state_topic"] = mqttTopic(magnitudeTopicIndex(i).c_str(), false); + root["unit_of_measurement"] = magnitudeUnits(type); + + root.printTo(output); + + } + + String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) + + "/sensor/" + + getSetting("hostname") + "_" + String(i) + + "/config"; + + mqttSendRaw(topic.c_str(), output.c_str()); + mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); + +} + +void _haSendMagnitudes() { + for (unsigned char i=0; i 1) { + name += String(" switch #") + String(i); + } + + root["name"] = name; root["platform"] = "mqtt"; if (relayCount()) { - root["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, 0, false); - root["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, 0, true); + root["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false); + root["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true); root["payload_on"] = String("1"); root["payload_off"] = String("0"); root["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false); @@ -52,17 +89,21 @@ void _haSend() { #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (lightHasColor()) { - root["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false); - root["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true); - root["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false); - root["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true); - root["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true); - } + if (i == 0) { + + if (lightHasColor()) { + root["brightness_state_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, false); + root["brightness_command_topic"] = mqttTopic(MQTT_TOPIC_BRIGHTNESS, true); + root["rgb_state_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, false); + root["rgb_command_topic"] = mqttTopic(MQTT_TOPIC_COLOR_RGB, true); + root["color_temp_command_topic"] = mqttTopic(MQTT_TOPIC_MIRED, true); + } + + if (lightChannels() > 3) { + root["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false); + root["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true); + } - if (lightChannels() > 3) { - root["white_value_state_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, false); - root["white_value_command_topic"] = mqttTopic(MQTT_TOPIC_CHANNEL, 3, true); } #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE @@ -78,11 +119,36 @@ void _haSend() { String topic = getSetting("haPrefix", HOMEASSISTANT_PREFIX) + "/" + component + - "/" + getSetting("hostname") + + "/" + getSetting("hostname") + "_" + String(i) + "/config"; mqttSendRaw(topic.c_str(), output.c_str()); mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); + +} + +void _haSendSwitches() { + for (unsigned char i=0; islot(magnitude.local); element["error"] = magnitude.sensor->error(); @@ -158,7 +140,7 @@ void _sensorAPISetup() { sensor_magnitude_t magnitude = _magnitudes[magnitude_id]; - String topic = _magnitudeTopic(magnitude.type); + String topic = magnitudeTopic(magnitude.type); if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) topic = topic + "/" + String(magnitude.global); apiRegister(topic.c_str(), [magnitude_id](char * buffer, size_t len) { @@ -181,9 +163,9 @@ void _sensorInitCommands() { sensor_magnitude_t magnitude = _magnitudes[i]; DEBUG_MSG_P(PSTR("[SENSOR] * %2d: %s @ %s (%s/%d)\n"), i, - _magnitudeTopic(magnitude.type).c_str(), + magnitudeTopic(magnitude.type).c_str(), magnitude.sensor->slot(magnitude.local).c_str(), - _magnitudeTopic(magnitude.type).c_str(), + magnitudeTopic(magnitude.type).c_str(), magnitude.global ); } @@ -546,7 +528,7 @@ void _magnitudesInit() { new_magnitude.filter->resize(_sensor_report_every); _magnitudes.push_back(new_magnitude); - DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), _magnitudeTopic(type).c_str(), _counts[type]); + DEBUG_MSG_P(PSTR("[SENSOR] -> %s:%d\n"), magnitudeTopic(type).c_str(), _counts[type]); _counts[type] = _counts[type] + 1; @@ -590,6 +572,38 @@ unsigned char magnitudeIndex(unsigned char index) { return 0; } +String magnitudeTopic(unsigned char type) { + char buffer[16] = {0}; + if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer)); + return String(buffer); +} + +String magnitudeTopicIndex(unsigned char index) { + char topic[32] = {0}; + if (index < _magnitudes.size()) { + sensor_magnitude_t magnitude = _magnitudes[index]; + if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { + snprintf(topic, sizeof(topic), "%s/%u", magnitudeTopic(magnitude.type).c_str(), magnitude.global); + } else { + snprintf(topic, sizeof(topic), "%s", magnitudeTopic(magnitude.type).c_str()); + } + } + return String(topic); +} + + +String magnitudeUnits(unsigned char type) { + char buffer[8] = {0}; + if (type < MAGNITUDE_MAX) { + if ((type == MAGNITUDE_TEMPERATURE) && (_sensor_temperature_units == TMP_FAHRENHEIT)) { + strncpy_P(buffer, magnitude_fahrenheit, sizeof(buffer)); + } else { + strncpy_P(buffer, magnitude_units[type], sizeof(buffer)); + } + } + return String(buffer); +} + // ----------------------------------------------------------------------------- void sensorSetup() { @@ -671,9 +685,9 @@ void sensorLoop() { dtostrf(current, 1-sizeof(buffer), decimals, buffer); DEBUG_MSG_P(PSTR("[SENSOR] %s - %s: %s%s\n"), magnitude.sensor->slot(magnitude.local).c_str(), - _magnitudeTopic(magnitude.type).c_str(), + magnitudeTopic(magnitude.type).c_str(), buffer, - _magnitudeUnits(magnitude.type).c_str() + magnitudeUnits(magnitude.type).c_str() ); } #endif // SENSOR_DEBUG @@ -693,20 +707,16 @@ void sensorLoop() { dtostrf(filtered, 1-sizeof(buffer), decimals, buffer); #if BROKER_SUPPORT - brokerPublish(_magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer); + brokerPublish(magnitudeTopic(magnitude.type).c_str(), magnitude.local, buffer); #endif #if MQTT_SUPPORT - if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { - mqttSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer); - } else { - mqttSend(_magnitudeTopic(magnitude.type).c_str(), buffer); - } + mqttSend(magnitudeTopicIndex(i).c_str(), buffer); #if SENSOR_PUBLISH_ADDRESSES char topic[32]; - snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, _magnitudeTopic(magnitude.type).c_str()); + snprintf(topic, sizeof(topic), "%s/%s", SENSOR_ADDRESS_TOPIC, magnitudeTopic(magnitude.type).c_str()); if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { mqttSend(topic, magnitude.global, magnitude.sensor->address(magnitude.local).c_str()); } else { @@ -718,9 +728,9 @@ void sensorLoop() { #if INFLUXDB_SUPPORT if (SENSOR_USE_INDEX || (_counts[magnitude.type] > 1)) { - idbSend(_magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer); + idbSend(magnitudeTopic(magnitude.type).c_str(), magnitude.global, buffer); } else { - idbSend(_magnitudeTopic(magnitude.type).c_str(), buffer); + idbSend(magnitudeTopic(magnitude.type).c_str(), buffer); } #endif // INFLUXDB_SUPPORT