Solar water heater application example cover image.

Smart Solar Water Heater with Home Assistant Integration

In this application we will demonstrate how to implement a smart solar water heater system and integrate it into your Home Assistant. We are going to use an EQSP32 industrial IoT controller for implementing the IoT automation and create the interfacing entities with Home Assistant.

How a Solar Water Heater system works

The solar water heater system harnesses solar energy to provide hot water, minimizing energy consumption during this task.

Solar water heating application example. System installation overview showcasing EQSP32 - Industrial IoT (IIoT) ESP32 PLC automation controller controlling circulation pump, boiler heater and home assistant (HA) integration. The iot controller monitors panel's and boiler's temperature for optimizing energy consumption and operation of the system.
Solar water heater installation overview integrated with Home Assistant

Solar panels installed on the roof capture solar energy, heating a fluid that circulates through the system. The heated fluid is pumped to a heat exchanger within a boiler, where it transfers its heat to the water stored in the boiler.

The boiler, equipped with a backup heating resistor, ensures a continuous supply of hot water even during periods of insufficient sunlight.

Temperature sensors monitor both the panel and boiler temperatures, activating the circulation pump only when necessary. This operation is based on predefined temperature thresholds to avoid unnecessary energy use. Furthermore, the boiler’s water temperature sensor provides a safety mechanism to prevent overheating.

Integrated with Home Assistant, the system allows users to monitor real-time temperature data and manually control the heater. This smart integration enhances user control and optimizes energy usage, making it a sustainable solution for domestic hot water needs.

Why use EQSP32 for this application

The EQSP32 industrial IoT controller offers comprehensive functionality for an end-to-end implementation of the desired solar water heater system. It directly reads the temperature sensors and controls the pump and heater relays through its versatile analog/digital IOs (ADIOs).

Another important feature is the seamless integration with Home Assistant. This functionality allows users to easily create the desired interfacing entities, displaying sensor values and the states of the pump and heater. Additionally, users can control the entire system through the Home Assistant platform, providing a user-friendly and efficient interface for managing the solar water heater.

With EQSP32 we can directly process and control the system, ensuring accurate and reliable operation in a standalone manner. Edge computing architecture (locally processing data) provides reduced latency, improved reliability and bandwidth efficiency. Additionally, by implementing the control loop locally in the EQSP32, we avoid the need to manually create the automation part in Home Assistant for each installation.

The ease of Home Assistant integration with EQSP32 allows us to extend the system’s functionality to our local Home Assistant server without solely relying on it. Running the automation locally on the EQSP32 reduces the risk of system failure in case of disconnection, while sharing the sensors and user controls with Home Assistant, harnessing all its advantages.

Solar Water Heater wiring diagram

The temperature sensors (thermistors) for the boiler and solar panels are connected to the controller’s analog input pins. Meanwhile, the EQSP32 controls the circulation pump and the electric heater via relays connected to its output pins. Additionally, the system is powered by a 24V DC supply, which is converted from an AC input, providing isolation from the grid.

EQSP32 - Industrial IoT ESP32 PLC wiring diagram for solar water heater application.
Smart solar water heater system wiring diagram with EQSP32 IoT controller

Easy Home Assistant integration with EQSP32

Software diagram of EQSP32 IIoT controller in a complete IoT system. Demonstrates how EQConnect mobile configuration app allows to setup wifi, device name and home assistant credentials for EQSP32 systems to connect with home assistant. EQSP32 library handles Home Assistant connection, publishes all defined interfaces and is responsible for receiving the commands and updating the sensor values in Home assistant.
Home Assistant interaction with EQSP32 and EQConnect configuration

The EQSP32 comes with an API to allow easy automation development and Home Assistant integration. The EQSP32 library automatically handles all network operations, automatic device discovery for Home Assistant and automatically publishes, reads and updates all system and user interfaces.

By using EQ-AI Erqos’ pretrained generative AI model, the coding experience is extremely simplified. We just need to describe and guide the GPT model, which already knows everything about EQSP32, to develop the code to our preferences and requirements.

Specifically for Home Assistant integration, EQSP32 library provides functions to create, read and update interfacing entities: createInterface(), readInterface() and updateInterface().

Once we have generated the user application and the EQSP32 library is running in the system, the system becomes available to Erqos’ EQConnect mobile configuration utility. Using EQConnect, we can enable automatic device discovery, setup Home Assistant and WiFi credentials and define our preferred device name for our system.

When automatic device discovery is enabled and EQSP32 is connected in the same WiFi network with our Home Assistant, the device will automatically appear.

For more information regarding the necessary setup and configurations, check out our tutorial:
Automatic Device Discovery and MQTT integration in Home Assistant“.

Our Solar Water Heater system in Home Assistant

At this point, we are going to demonstrate the Home Assistant integration first, and then we will dive into the automation code and how to make the Solar Water Heater interact with Home Assistant.

Solar water heating application example. Demonstrating solar water heater IoT system in Home Assistant integration. EQSP32 - Industrial IoT (IIoT) ESP32 PLC automation controller automatically publishes all configured entities and they become available for monitoring and control in Home Assistant (HA). We see panel and boiler temperatures, user's heater control, circulation pump state and electric heater state.
Screenshot of discovered EQSP32 in Home Assistant

The Solar Water Heater IoT system automatically appears in our Home Assistant. Apart from the system parameters (Input & Output Voltage and Signal Strength), which are published automatically, we see various other entities.

To allow the user to enable and disable the resistive heater in the boiler, we have created a control interface that operates as a virtual switch.

For monitoring interfaces, we have both panel and boiler temperatures available, as well as the relay states of the heater and the pump.

Now let’s take a look on how all this functionality is implemented!

Solar Water Heater system and Home Assistant operation

Below are the steps necessary to operate the solar water heater and interface it with Home Assistant.

Smart solar water heater IoT system operation diagram. Using EQSP32 industrial IoT controller to run the control loop for the smart solar water heater iot system.
Solar water heater & Home Assistant functional diagram
  1. Read Panel and Boiler Temperatures
  2. Check for Heater Control
    • Check if the user has manually requested the heater to be turned on through a virtual switch in Home Assistant.
  3. Control Circulation Pump
    • If the boiler temperature is below the safety threshold, the circulation pump is enabled only if the solar panel temperature is significantly higher than the boiler temperature.
    • The pump is turned off if the boiler temperature exceeds the maximum allowable temperature.
  4. Control Resistive Heater
    • If the user has requested the heater to turn on, the system enables the heater under certain conditions:
      • The circulation pump must be off (water is not being heated by solar panels).
      • The boiler temperature must not exceed the heater’s safety limit.
      • If these conditions are met, the heater is turned on; otherwise, it is turned off.
  5. Update Home Assistant
    • The system updates Home Assistant if the “Heat Limit” in the boiler was reached and provides feedback for the user’s “Heater Control”.

Automation code and Home Assistant integration

Includes and Initialization

#include "EQSP32.h"

EQSP32 eqsp32;
  • #include "EQSP32.h": This line includes the EQSP32 library, which provides all API functions and background tasks necessary to control the EQSP32 controller.
  • EQSP32 eqsp32: This creates an instance of the EQSP32 class, named eqsp32, which will be used to access the controller’s functions.

Pin assignment

#define PIN_BOILER_TEMP 1  // Temperature sensor for the boiler
#define PIN_PANEL_TEMP 2   // Temperature sensor for the solar panel
#define PIN_HEATER 3       // Relay for the electric heater
#define PIN_PUMP 4         // Relay for the circulation pump
  • PIN_BOILER_TEMP: Assigned to pin 1, this is used for the temperature sensor connected to the boiler.
  • PIN_PANEL_TEMP: Assigned to pin 2, this is used for the temperature sensor connected to the solar panel.
  • PIN_HEATER: Assigned to pin 3, this pin controls the relay for the electric heater.
  • PIN_PUMP: Assigned to pin 4, this pin controls the relay for the circulation pump.

Constants

// Temperature-related constants
const float HYSTERISIS = 2.0;
const float TEMP_DIFF_THRESHOLD = 10.0; // Temperature difference threshold between panel and boiler
const float BOILER_MAX_TEMP = 60.0;     // Maximum boiler temperature for pump operation
const float HEATER_ON_TEMP = 35.0;      // Temperature below which heater should turn on
const float HEATER_OFF_TEMP = 45.0;     // Temperature above which heater should turn off
const float HEATER_HYSTERESIS_ON = HEATER_ON_TEMP - 2.0; // Lower threshold for heater to turn on
const float HEATER_HYSTERESIS_OFF = HEATER_OFF_TEMP + 2.0; // Upper threshold for heater to turn off
  • HYSTERISIS: A constant value of 2.0 used to create a buffer around temperature thresholds to prevent rapid switching of the pump and heater. This helps to maintain system stability.
  • TEMP_DIFF_THRESHOLD: A constant value of 10.0°C representing the minimum temperature difference between the solar panel and the boiler required to activate the circulation pump. This ensures that the pump only operates when there is enough solar energy to heat the water effectively.
  • BOILER_MAX_TEMP: A constant value of 60.0°C representing the maximum allowable temperature for the boiler. If the boiler temperature exceeds this value, the pump will be turned off to prevent overheating.
  • HEATER_ON_TEMP: A constant value of 35.0°C representing the temperature below which the electric heater should be turned on to ensure the water is sufficiently heated.
  • HEATER_OFF_TEMP: A constant value of 45.0°C representing the temperature above which the electric heater should be turned off to prevent overheating.

Setup ADIOs and Home Assistant interfaces

void setup() {
    EQSP32Configs myEQSP32Configs;
    myEQSP32Configs.devSystemID = "SolarHeaterV1.0";
    eqsp32.begin(myEQSP32Configs, true); // Initialize with verbose enabled

    // Configure pin modes
    eqsp32.pinMode(PIN_BOILER_TEMP, TIN);
    eqsp32.configTIN(PIN_BOILER_TEMP, 3988, 10000); // Example NTC parameters

    eqsp32.pinMode(PIN_PANEL_TEMP, TIN);
    eqsp32.configTIN(PIN_PANEL_TEMP, 3988, 10000); // Example NTC parameters

    eqsp32.pinMode(PIN_HEATER, RELAY);
    eqsp32.configRELAY(PIN_HEATER, 500, 1000); // Example relay config

    eqsp32.pinMode(PIN_PUMP, RELAY);
    eqsp32.configRELAY(PIN_PUMP, 500, 1000); // Example relay config

    // Create interfaces for Home Assistant
    createInterface("Boiler Temperature", PIN_BOILER_TEMP);
    createInterface("Panel Temperature", PIN_PANEL_TEMP);
    createInterface("Electric Heater", PIN_HEATER);
    createInterface("Circulation Pump", PIN_PUMP);
    createInterface("Heater Control", "switch"); // Virtual switch for manual control

    BinarySensorEntity myBinSensor;
    myBinSensor.devClass = "heat";
    createInterface("Heat Limit", myBinSensor);

    // Initial values
    eqsp32.pinValue(PIN_HEATER, 0); // Heater off
    eqsp32.pinValue(PIN_PUMP, 0);   // Pump off
}

ADIO configuration

  • PIN_BOILER_TEMP & PIN_PANEL_TEMP : Configured as a temperature input node (TIN) and specify the NTC parameters.
    • eqsp32.pinMode(PIN_BOILER_TEMP, TIN): Sets pin 1 to read the boiler temperature using a thermistor.
    • eqsp32.configTIN(PIN_BOILER_TEMP, 3988, 10000): Configures the thermistor with specific parameters (e.g., B-value of 3988 and resistance of 10k ohms).
  • PIN_HEATER & PIN_PUMP: Configured as a relay output mode (RELAY) and specify power derating power and delay .
    • eqsp32.pinMode(PIN_HEATER, RELAY): Sets pin 3 to control the electric heater via a relay.
    • eqsp32.configRELAY(PIN_HEATER, 500, 1000): Configures the relay with specific parameters (e.g., derated power 50% after 1 second).

Home Assistant integration

  • createInterface("Boiler Temperature", PIN_BOILER_TEMP): Creates an interface in Home Assistant to monitor the boiler temperature.
  • createInterface("Panel Temperature", PIN_PANEL_TEMP): Creates an interface in Home Assistant to monitor the solar panel temperature.
  • createInterface("Electric Heater", PIN_HEATER): Creates an interface to display the state of the electric heater relay in Home Assistant.
  • createInterface("Circulation Pump", PIN_PUMP): Creates an interface to display the state of the circulation pump relay in Home Assistant.
  • createInterface("Heater Control", "switch"): Creates a virtual switch in Home Assistant for manual control of the heater.
  • BinarySensorEntity myBinSensor:
    • myBinSensor.devClass = "heat": Sets the device class to “heat”.
    • createInterface("Heat Limit", myBinSensor): Creates a custom binary sensor (On/Off) interface in Home Assistant to monitor the heat limit. This entity will be triggered if the boiler has stop heating due to reaching the respective temperature threshold (different threshold while heating from the resistive heater than when using the solar panels).

Solar Water Heater control loop and Home Assistant interaction

    Control logic for circulation pump

    void loop() {
        // Read temperatures
        float boilerTemp = eqsp32.readPin(PIN_BOILER_TEMP);
        float panelTemp = eqsp32.readPin(PIN_PANEL_TEMP);
        
        // Read manual heater control from Home Assistant virtual switch
        bool manualHeaterControl = readInterfaceBOOL("Heater Control");
    
        // Read current states of the pump and heater
        bool pumpState = (eqsp32.readPin(PIN_PUMP) > 0);
    
        // Control logic for circulation pump
        if (boilerTemp < BOILER_MAX_TEMP - HYSTERISIS) {
            if (panelTemp > boilerTemp + TEMP_DIFF_THRESHOLD + HYSTERISIS) {
                eqsp32.pinValue(PIN_PUMP, 1000); // Turn on pump
            } else if (panelTemp < boilerTemp + TEMP_DIFF_THRESHOLD) {
                eqsp32.pinValue(PIN_PUMP, 0);    // Turn off pump
            }
        } else if (boilerTemp > BOILER_MAX_TEMP) {
            eqsp32.pinValue(PIN_PUMP, 0);    // Turn off pump
        }
    
        // Remaining code ...
    }
    • Safety Check
      • The code first checks if the boiler temperature is below the maximum allowable temperature minus the hysteresis value (BOILER_MAX_TEMP - HYSTERISIS). This ensures that the boiler does not overheat.
    • Temperature Difference Check
      • If the boiler temperature is safe, the code then checks the temperature difference between the solar panel and the boiler.
      • If the panel temperature is significantly higher than the boiler temperature (panelTemp > boilerTemp + TEMP_DIFF_THRESHOLD + HYSTERISIS), the circulation pump is turned on (eqsp32.pinValue(PIN_PUMP, 1000)).
      • If the temperature difference is not sufficient (panelTemp < boilerTemp + TEMP_DIFF_THRESHOLD), the pump is turned off (eqsp32.pinValue(PIN_PUMP, 0)).
    • Overheating Protection
      • If the boiler temperature exceeds the maximum allowable temperature (boilerTemp > BOILER_MAX_TEMP), the pump is turned off to prevent overheating (eqsp32.pinValue(PIN_PUMP, 0)).

    Control logic for resistive heater

    void loop() {
        // Control logic circulation pump code ...
    
        // Control logic for electric heater with hysteresis
        if (manualHeaterControl && !pumpState) {
    		if (boilerTemp > HEATER_OFF_TEMP)
    			eqsp32.pinValue(PIN_HEATER, 0); // Turn off heater
    		else if (boilerTemp < HEATER_ON_TEMP - HYSTERISIS)
    			eqsp32.pinValue(PIN_HEATER, 1000); // Turn on heater
        } else {
            eqsp32.pinValue(PIN_HEATER, 0); // Ensure heater is off if manual control is off or pump is circulating
        }
    
        // Remaining code ...
    }
    • Manual Control Check
      • The heater is controlled manually via Home Assistant. The condition manualHeaterControl && !pumpState ensures that the heater operates only if manual control is enabled and the pump is not circulating water.
    • Boiler Temperature Check
      • If manual control is enabled and the pump is off, the system checks the boiler temperature:
        • Turn Off Heater: If the boiler temperature exceeds the heater off threshold (boilerTemp > HEATER_OFF_TEMP), the heater is turned off (eqsp32.pinValue(PIN_HEATER, 0)).
        • Turn On Heater: If the boiler temperature is below the heater on threshold minus hysteresis (boilerTemp < HEATER_ON_TEMP - HYSTERISIS), the heater is turned on (eqsp32.pinValue(PIN_HEATER, 1000)).
    • Ensure Heater is Off
      • If manual control is off or the pump is circulating, the heater is turned off to prevent simultaneous operation of the pump and heater (eqsp32.pinValue(PIN_HEATER, 0)).

    Update Home Assistant

    void loop() {
        // Control logic circulation pump code ...
    
        // Control logic resistive heater code ...
    
        // Update Heat Limit interface based on boiler temperature
        if ( (manualHeaterControl && !pumpState && boilerTemp > HEATER_OFF_TEMP) || \
              (boilerTemp > BOILER_MAX_TEMP && panelTemp > boilerTemp + TEMP_DIFF_THRESHOLD + HYSTERISIS)  )    // Boiler hot triggers if manual control or panel pump should be enabled but is not due to high boiler temperature
            updateInterfaceBOOL("Heat Limit", true);
        else
            updateInterfaceBOOL("Heat Limit", false);
        
        updateInterfaceBOOL("Heater Control", manualHeaterControl); // Update control value with what we have received for feedback
    
        delay(10); // Small delay for non-blocking operation
    }
    • Heat Limit Interface Update
      • The system updates the “Heat Limit” interface in Home Assistant. The conditions for setting the “Heat Limit” to true are:
        • Manual heater control is enabled, the pump is not running, and the boiler temperature exceeds the heater off threshold.
        • The boiler temperature exceeds the maximum allowable temperature and the panel temperature is sufficiently higher than the boiler temperature.
    • Heater Control Feedback
      • The system updates the “Heater Control” interface in Home Assistant to reflect the current manual control state

    Complete smart Solar Water Heater code with Home Assistant interfaces

    #include "EQSP32.h"
    
    EQSP32 eqsp32;
    
    // Pin assignments
    #define PIN_BOILER_TEMP 1  // Temperature sensor for the boiler
    #define PIN_PANEL_TEMP 2   // Temperature sensor for the solar panel
    #define PIN_HEATER 3       // Relay for the electric heater
    #define PIN_PUMP 4         // Relay for the circulation pump
    
    // Temperature-related constants
    const float HYSTERISIS = 2.0;
    const float TEMP_DIFF_THRESHOLD = 10.0; // Temperature difference threshold between panel and boiler
    const float BOILER_MAX_TEMP = 60.0;     // Maximum boiler temperature for pump operation
    const float HEATER_ON_TEMP = 35.0;      // Temperature below which heater should turn on
    const float HEATER_OFF_TEMP = 45.0;     // Temperature above which heater should turn off
    
    void setup() {
        EQSP32Configs myEQSP32Configs;
        myEQSP32Configs.devSystemID = "SolarHeaterV1.0";
        eqsp32.begin(myEQSP32Configs, true); // Initialize with verbose enabled
    
        // Configure pin modes
        eqsp32.pinMode(PIN_BOILER_TEMP, TIN);
        eqsp32.configTIN(PIN_BOILER_TEMP, 3988, 10000); // Example NTC parameters
    
        eqsp32.pinMode(PIN_PANEL_TEMP, TIN);
        eqsp32.configTIN(PIN_PANEL_TEMP, 3988, 10000); // Example NTC parameters
    
        eqsp32.pinMode(PIN_HEATER, RELAY);
        eqsp32.configRELAY(PIN_HEATER, 500, 1000); // Example relay config
    
        eqsp32.pinMode(PIN_PUMP, RELAY);
        eqsp32.configRELAY(PIN_PUMP, 500, 1000); // Example relay config
    
        // Create interfaces for Home Assistant
        createInterface("Boiler Temperature", PIN_BOILER_TEMP);
        createInterface("Panel Temperature", PIN_PANEL_TEMP);
        createInterface("Electric Heater", PIN_HEATER);
        createInterface("Circulation Pump", PIN_PUMP);
        createInterface("Heater Control", "switch"); // Virtual switch for manual control
    
        BinarySensorEntity myBinSensor;
        myBinSensor.devClass = "heat";
        createInterface("Heat Limit", myBinSensor);
    
        // Initial values
        eqsp32.pinValue(PIN_HEATER, 0); // Heater off
        eqsp32.pinValue(PIN_PUMP, 0);   // Pump off
    }
    
    void loop() {
        // Read temperatures
        float boilerTemp = eqsp32.readPin(PIN_BOILER_TEMP);
        float panelTemp = eqsp32.readPin(PIN_PANEL_TEMP);
    
        // Read manual heater control from Home Assistant virtual switch
        bool manualHeaterControl = readInterfaceBOOL("Heater Control");
    
        // Read current states of the pump and heater
        bool pumpState = (eqsp32.readPin(PIN_PUMP) > 0);
    
        // Control logic for circulation pump
    	if (boilerTemp < BOILER_MAX_TEMP - HYSTERISIS)
    	{
    		if (panelTemp > boilerTemp + TEMP_DIFF_THRESHOLD + HYSTERISIS) {
    			eqsp32.pinValue(PIN_PUMP, 1000); // Turn on pump
    		} else if (panelTemp < boilerTemp + TEMP_DIFF_THRESHOLD) {
    			eqsp32.pinValue(PIN_PUMP, 0);    // Turn off pump
    		}
    	}
    	else if (boilerTemp > BOILER_MAX_TEMP)
    		eqsp32.pinValue(PIN_PUMP, 0);    // Turn off pump
    
        // Control logic for electric heater with hysteresis
        if (manualHeaterControl && !pumpState) {
    		if (boilerTemp > HEATER_OFF_TEMP)
    			eqsp32.pinValue(PIN_HEATER, 0); // Turn off heater
    		else if (boilerTemp < HEATER_ON_TEMP - HYSTERISIS)
    			eqsp32.pinValue(PIN_HEATER, 1000); // Turn on heater
        } else {
            eqsp32.pinValue(PIN_HEATER, 0); // Ensure heater is off if manual control is off or pump is circulating
        }
    
        // Update Heat Limit interface based on boiler temperature
        if ( (manualHeaterControl && !pumpState && boilerTemp > HEATER_OFF_TEMP) || \
              (boilerTemp > BOILER_MAX_TEMP && panelTemp > boilerTemp + TEMP_DIFF_THRESHOLD + HYSTERISIS)  )    // Boiler hot triggers if manual control or panel pump should be enabled but is not due to high boiler temperature
            updateInterfaceBOOL("Heat Limit", true);
        else
            updateInterfaceBOOL("Heat Limit", false);
        
        updateInterfaceBOOL("Heater Control", manualHeaterControl); // Update control value with what we have received for feedback
    
        delay(10); // Small delay for non-blocking operation
    }
    

    Add a Comment

    Your email address will not be published. Required fields are marked *