Skip to content

Commit

Permalink
HA auto-discover for multi-relay boards and sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
xoseperez committed Jan 26, 2018
1 parent eccd4e7 commit cd54372
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 54 deletions.
106 changes: 86 additions & 20 deletions code/espurna/homeassitant.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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<magnitudeCount(); i++) {
_haSendMagnitude(i);
}
}

#endif

void _haSendSwitch(unsigned char i) {

String output;

Expand All @@ -37,12 +69,17 @@ void _haSend() {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();

root["name"] = getSetting("hostname");
String name = getSetting("hostname");
if (relayCount() > 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);
Expand All @@ -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
Expand All @@ -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; i<relayCount(); i++) {
_haSendSwitch(i);
}
}

void _haSend() {

// Pending message to send?
if (!_haSendFlag) return;

// Are we connected?
if (!mqttConnected()) return;

DEBUG_MSG_P(PSTR("[HA] Sending autodiscovery MQTT message\n"));

// Send messages
_haSendSwitches();
#if SENSOR_SUPPORT
_haSendMagnitudes();
#endif

_haSendFlag = false;

}
Expand Down
78 changes: 44 additions & 34 deletions code/espurna/sensor.ino
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,11 @@ double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
// Private
// -----------------------------------------------------------------------------

String _magnitudeTopic(unsigned char type) {
char buffer[16] = {0};
if (type < MAGNITUDE_MAX) strncpy_P(buffer, magnitude_topics[type], sizeof(buffer));
return String(buffer);
}

unsigned char _magnitudeDecimals(unsigned char type) {
if (type < MAGNITUDE_MAX) return pgm_read_byte(magnitude_decimals + type);
return 0;
}

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);
}

double _magnitudeProcess(unsigned char type, double value) {
if (type == MAGNITUDE_TEMPERATURE) {
if (_sensor_temperature_units == TMP_FAHRENHEIT) value = value * 1.8 + 32;
Expand Down Expand Up @@ -91,7 +73,7 @@ void _sensorWebSocketSendData(JsonObject& root) {
element["index"] = int(magnitude.global);
element["type"] = int(magnitude.type);
element["value"] = String(buffer);
element["units"] = _magnitudeUnits(magnitude.type);
element["units"] = magnitudeUnits(magnitude.type);
element["description"] = magnitude.sensor->slot(magnitude.local);
element["error"] = magnitude.sensor->error();

Expand Down Expand Up @@ -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) {
Expand All @@ -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
);
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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

Expand Down

0 comments on commit cd54372

Please sign in to comment.