Browse Source

HA auto-discover for multi-relay boards and sensors

i18n
Xose Pérez 7 years ago
parent
commit
cd54372588
2 changed files with 130 additions and 54 deletions
  1. +86
    -20
      code/espurna/homeassitant.ino
  2. +44
    -34
      code/espurna/sensor.ino

+ 86
- 20
code/espurna/homeassitant.ino View File

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


+ 44
- 34
code/espurna/sensor.ino View File

@ -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;
@ -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();
@ -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


Loading…
Cancel
Save