dumpfheimer / olimpia_splendid_bi2_modbus_controller

Modbus Controller for Olimpia Splendid BI2 fancoils and similar devices.
7 stars 3 forks source link

Adding MQTT Discovery for Home Assistant #4

Open r0bb10 opened 8 months ago

r0bb10 commented 8 months ago

Hi man! Take a look at this configuration below, this should fix the Home Assistant configuration with sendHomeAssistantConfiguration() by using the correct MQTT Auto Discovery function (details here) that i have tested manually by publishing a JSON in the correct homeassistant topic.

The whole sendHomeAssistantConfiguration() should be replaced by something like sendAutoDiscoveryMsg(), i tried to write it correctly here:

void sendAutoDiscoveryMsg() {
  DynamicJsonDocument doc(1024);
  char buffer[256];

  doc["name"] = "Fancoil " + addr + "";
  doc["unique_id"] = "hvac_" + clientId + "-" + addr + "";
  doc["availability_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/state";
  doc["payload_available"] = "online";
  doc["payload_not_available"] = "offline";
  doc["mode_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/mode/set";
  doc["mode_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/mode/state";
  doc["modes"] = "heat", "cool", "off";
  doc["min_temp"] = "15";
  doc["max_temp"] = "30";
  doc["precision"] = "0.5";
  doc["retain"] = "true";
  doc["temperature_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/setpoint/set";
  doc["temperature_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/setpoint/state";
  doc["temp_step"] = "0.5";
  doc["fan_mode_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/fan_speed/set";
  doc["fan_mode_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/fan_speed/state";
  doc["fan_modes"] = "auto", "high", "low", "night";
  JsonObject device  = doc.createNestedObject("device");
  device["name"] = "Fancoil " + addr + "";
  device["via_device"] = "Fancoil CTRL";
  device["identifiers"] = "hvac_" + clientId + "-" + addr + "";
  device["model"] = "B0872 ModBus";
  device["manufacturer"] = "Olimpia Splendid";
  device["model"] = "Olimpia Splendid";
  device["sw_version"] = "1.0";
  serializeJson(doc, buffer);
  client.publish("homeassistant/climate/hvac_" + clientId + "-" + addr + "/config", buffer);

#ifdef LOAD_WATER_TEMP
  doc["name"] = "Water Sensor";
  doc["unique_id"] = "hvac_" + clientId + "-" + addr + "_water_sensor";
  doc["device_class"] = "temperature";
  doc["state_class"] = "measurement";
  doc["unit_of_measurement"] = "C";
  doc["state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/water_sensor/state";
  serializeJson(doc, buffer);
  client.publish("homeassistant/sensor/hvac_" + clientId + "-" + addr + "_water_sensor/config", buffer);
#endif

#ifdef LOAD_AMBIENT_TEMP
  doc["name"] = "Ambient Sensor";
  doc["unique_id"] = "hvac_" + clientId + "-" + addr + "_ambient_sensor";
  doc["device_class"] = "temperature";
  doc["state_class"] = "measurement";
  doc["unit_of_measurement"] = "C";
  doc["state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/ambient_sensor/state";
  serializeJson(doc, buffer);
  client.publish("homeassistant/sensor/hvac_" + clientId + "-" + addr + "_ambient_sensor/config", buffer);
#endif
}

The discovery should auto-populate the correct entity in the MQTT integration and should have the ambient/water sensor also if defined, i'm not sure about how many fancoils should be pushed tho, i think it should publish the registered ones if did not mess up anything. The format is JSON that has to be serialized before it can be published in the correct topic but looking online it should work as is. Manually sending the JSON works as expected, this is an example:

{
    "name": "Fancoil 1",
    "send_if_off": true,
    "unique_id": "hvac_C8-C9-A3-54-1B-C7-1",
    "availability_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/state/state",
    "payload_available": "online",
    "payload_not_available": "offline",
    "current_temperature_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/ambient_temperature/state",
    "fan_mode_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/fan_speed/set",
    "fan_mode_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/fan_speed/state",
    "fan_modes": ["auto", "high", "low", "night"],
    "mode_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/mode/set",
    "mode_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/mode/state",
    "modes": ["heat", "cool", "off"],
    "min_temp": 15,
    "max_temp": 30,
    "precision": 0.5,
    "retain": true,
    "temperature_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/setpoint/set",
    "temperature_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/1/setpoint/state",
    "temp_step": 0.5,
    "device": {
        "manufacturer": "Olimpia Splendid",
        "via_device": "Fancoil CTRL",
        "identifiers": "hvac_C8-C9-A3-54-1B-C7-1",
        "name": "Fancoil 1",
        "model": "B0872 ModBus",
        "sw_version": "1.0"
    }
}

image image

I did not make a push request because i'm not sure how to implement and remove the old parts, but this should completely avoid to manually create mqtt.yaml entity and find out the correct topics in the broker, polishing the deploy.

Cheers!

dumpfheimer commented 7 months ago

Hi there!

Sorry for the late reply. This looks quite nice! Would you be able to open a pull request?

Is this using the ArduinoJson library?

Thanks for your effort.

r0bb10 commented 7 months ago

Hi!

So those below are the JSON sent via mqtt discovery (each has to be sent in a topic called "homeassistant/climate/NAME/config" - for the climate entity - and "homeassistant/sensor/NAME/config" - for the sensor entity), the arduino version is using the ArduinoJson library to serialize and have this published but there are some problems.

Ok first of all i dont know how to code it correctly, specifically have the arduino code "know" the fancoil address to publish in each config topic, but that is probably easy for you to understand. I "think" the document is correct with all the doc part necessary present, but i'm not really sure.

The problem is that the config subtopic in the homeassistant topic is volatile and does not survive a homeassistant restart, even if the mqtt broker does not reboot.. for example i use hassio supervised and homeassistant core and mosquitto are 2 different containers, on update just core reboots and mosquitto stays up but even so the homeassistant topic is cleared. So the AutoDiscovery has to be tied to homeassistant somehow, and the config message has to be resent. Now sendHomeAssistantConfiguration() (which i noticed is needed in the code so cannot be removed) is sent to mosquitto on mqtt reconnect but that would not work if homeassistant restarts for whatever reason (update, crash, manual restart) so the arduino code should push sendAutoDiscoveryMsg() in a different way.. time based? every 5 min? mm not clean i guess, somehow the loop should know when hass needs the config and when to push it. I have other mqtt autodiscovered entities that do that correctly (namely Valetudo for the vacuum entity does it right), the topic is cleared but it shows up after a little while.

I did not add the LOAD_AMBIENT_TEMP since i noticed that in rE mode that value in register 0 is a mirrored value of register 103 is it's ignoring the onboard sensor. Need more confirmation on that tho.

void sendAutoDiscoveryMsg() {
  DynamicJsonDocument doc(1024);
  char buffer[256];

  doc["name"] = "Fancoil " + addr + "";
  doc["icon"] = "mdi:home-thermometer-outline";
  doc["send_if_off"] = "true";
  doc["unique_id"] = "hvac_" + clientId + "-" + addr + "";
  doc["availability_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/state";
  doc["payload_available"] = "online";
  doc["payload_not_available"] = "offline";
  doc["mode_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/mode/set";
  doc["mode_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/mode/state";
  doc["action_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/action/state";
  doc["modes"] = "heat", "cool", "off";
  doc["min_temp"] = "15";
  doc["max_temp"] = "30";
  doc["precision"] = "0.1";
  doc["retain"] = "true";
  doc["temperature_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/setpoint/set";
  doc["temperature_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/setpoint/state";
  doc["temp_step"] = "0.5";
  doc["fan_mode_command_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/fan_speed/set";
  doc["fan_mode_state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/fan_speed/state";
  doc["fan_modes"] = "auto", "high", "low", "night";
  JsonObject device  = doc.createNestedObject("device");
  device["name"] = "Fancoil " + addr + "";
  device["via_device"] = "Fancoil CTRL";
  device["identifiers"] = "hvac_" + clientId + "-" + addr + "";
  device["model"] = "Bi2 SL Smart 400";
  device["manufacturer"] = "Olimpia Splendid";
  serializeJson(doc, buffer);
  client.publish("homeassistant/climate/hvac_" + clientId + "-" + addr + "/config", buffer);

#ifdef LOAD_WATER_TEMP
  doc["name"] = "Water Sensor";
  doc["unique_id"] = "watersensor_" + clientId + "-" + addr + "";
  doc["send_if_off"] = "true";
  doc["device_class"] = "temperature";
  doc["state_class"] = "measurement";
  doc["unit_of_measurement"] = "°C";
  doc["suggested_display_precision"] = 0;
  doc["state_topic"] = "fancoil_ctrl/" + clientId + "/" + addr + "/water_sensor/state";
  serializeJson(doc, buffer);
  client.publish("homeassistant/sensor/watersensor_" + clientId + "-" + addr + "/config", buffer);
#endif

image


{
  "name": "HVAC",
  "icon": "mdi:home-thermometer-outline",
  "send_if_off": true,
  "unique_id": "hvac_C8-C9-A3-54-1B-C7-5",
  "availability_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/state/state",
  "payload_available": "online",
  "payload_not_available": "offline",
  "current_temperature_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/ambient_temperature/state",
  "fan_mode_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/fan_speed/set",
  "fan_mode_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/fan_speed/state",
  "fan_modes": [
    "auto",
    "high",
    "low",
    "night"
  ],
  "action_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/action/state",
  "mode_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/mode/set",
  "mode_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/mode/state",
  "modes": [
    "heat",
    "cool",
    "off"
  ],
  "min_temp": 15,
  "max_temp": 30,
  "precision": 0.1,
  "retain": true,
  "temperature_command_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/setpoint/set",
  "temperature_state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/setpoint/state",
  "temp_step": 0.5,
  "device": {
    "manufacturer": "Olimpia Splendid",
    "via_device": "Fancoil CTRL",
    "identifiers": "hvac_C8-C9-A3-54-1B-C7-5",
    "name": "Fancoil Studio",
    "model": "Bi2 SL Smart 400"
  }
}

{
  "name": "Water Sensor",
  "unique_id": "watersensor_C8-C9-A3-54-1B-C7-5",
  "send_if_off": true,
  "device_class": "temperature",
  "state_topic": "fancoil_ctrl/C8-C9-A3-54-1B-C7/5/water_sensor/state",
  "unit_of_measurement": "°C",
  "suggested_display_precision": 0,
  "device": {
    "manufacturer": "Olimpia Splendid",
    "via_device": "Fancoil CTRL",
    "identifiers": "hvac_C8-C9-A3-54-1B-C7-5",
    "name": "Fancoil Studio",
    "model": "Bi2 SL Smart 400"
  }
}