Write a boiler temperature control system

1. Preface

My family is in the Northeast countryside. It's very cold in winter. I bought a boiler and needed a circulating pump. Simply put, after the boiler is hot, the circulating pump will automatically start, and then the hot water will be transported away to the heating. The hot water will be pumped away, the cold water will enter the boiler, the temperature will decrease, the circulating pump will be closed, and wait for the next water heating. Because the house to be heated is far away from the place where the boiler is burned, a circulating pump is required. If the distance is close, the circulation will be completed automatically by using the principle of hot water upflow and cold water backflow after the water is heated. Of course, there are such devices on the market that use temperature to automatically control the opening and closing of circulating pump:

The principle is that there is a thermistor probe (with magnet adsorption, which can be adsorbed to the boiler wall) and then controlled by a relay. When the temperature reaches the set value, the relay is opened and the circulating pump is started. After circulation, the boiler wall temperature drops, the relay is closed and the circulating pump is closed.

Circulating pump:

Because the circulating pump in my house has a large power, the small relay burned out after starting several times, so a layer of AC contactor (added by my old father) was connected in the middle.

This kind of equipment on the market can roughly solve the problem of water circulation, but some details can not be solved. For example, when the water temperature of the return pipe also reaches the set temperature value, the circulating pump will always be on. At this time, it is necessary to manually adjust the knob temperature (increase) to stop the circulating pump (high-power circulating pump consumes a lot of power). For another example, when the coal inside the furnace is gradually burned (it is called waterlogging in Northeast Chinese), the boiler temperature cannot reach the set value. At this time, it is necessary to reduce the knob and start the circulating pump so that the residual temperature generated by these coal will not be wasted.

Due to the above shortcomings, someone needs to adjust the knob every few hours. This part of the work is done by my old father, so I want to do an automatic thing to reduce my old father's workload.

2. Project structure

My original idea was that the temperature could be adjusted remotely through my mobile phone, so at least I didn't have to adjust the knob manually. I got up in the middle of the night and adjusted it with my mobile phone in my quilt. The structure designed based on the original idea:

3. Hardware construction

esp01 module + relay module, 220v to 5v module + plug-in = networking socket

esp8226 + temperature sensor + nixie tube = real-time temperature detection and display networking module

My control system is written in esp8226.

Fabrication of temperature sensor probe: to drive the ds18b20 sensor, a 4.7k ohm resistance (pull-up resistance) needs to be added between the data bus (DQ) and VDD pin. This is necessary. It is wrapped with an iron button with two small neodymium magnets inside. Finally, it is filled with good glue, so as to form a temperature sensor probe, Can be adsorbed on the boiler wall:

I made a mistake in this step. I put the ds18b20 sensor and pull-up resistance into the probe. When measuring the temperature, it was found that the temperature sensor failed to read the temperature after the temperature increased, because the resistance value increased due to the increase of temperature. Later, I put the resistor at the tail to solve this problem.

Encapsulated probe:

esp8226 + nixie tube module:

I printed the shell with a 3D printer and placed the esp8226 module inside.

4. Software preparation

firmware

esp8226 and esp01 are micro Python firmware that I burn.

signal communication

At the beginning of communication, I want to implement it with socket and simply get an HTTP protocol for communication, but such control on the mobile phone is troublesome. There is no easy-to-use software. I also need to make a web interface. In addition, socket will block threads.

Later, I found mqtt, A hardware network communication protocol for the Internet of things, which can cope with high latency network environment. Briefly introduce the mqtt protocol. First, you need A server (also called proxy server, which runs on the computer. Here I run on raspberry pie). Then all your IOT hardware devices (such as esp8226) are clients. There will be no direct communication between IOT hardware devices (clients). They all communicate directly with the server, If communication is needed between hardware devices, it is necessary to publish or subscribe to topics. For example, if hardware A and hardware B need to communicate, they need to be connected to the server first, and then A publishes A topic called topic. If hardware B wants to accept A's information, it needs to subscribe to the topic, so as to realize the communication between A -- > B. reverse communication is also A principle. B publishes topics and A subscribes. Another advantage of this protocol is that it can subscribe to multiple clients for one topic, so as to realize multi terminal communication. In mqtt protocol communication, each client does not know the existence of other clients. They all communicate directly with the server.

There is a big problem in the communication of mqtt protocol in the micro Python firmware (I don't know whether the default firmware of Anxin also exists): LmacRxBlk:1 reports an error. For example, if you subscribe to a topic at the beginning, and then you use the non blocking method check_msg() processes the subscribed topic messages through the callback function. At this time, if the number of topic publications you subscribe to exceeds your check_msg(), an error LmacRxBlk:1 will be reported at the bottom of the micro Python firmware, and then the communication will be interrupted. In short, you enter the event loop after subscribing to a topic, and you have no time to process the message of subscribing to the topic, which will lead to this error. The official explanation of this error is that the tcp buffer resources are not released, because the available resources of the ESP 8226 are very limited. However, in mqtt communication, it is impossible for me to release the connection after each cycle and then re-establish the connection every time. The disgusting thing about this error is that try exception cannot be captured, Then, this error can only be solved by design, that is to ensure that the published interval of the subscribed topic is far less than its cyclic interval at the beginning, so as to ensure that the subscribed messages can be processed in time every time. I have solved this problem for a long time, because try exception cannot be captured, and it does not often occur. It cannot be located. I do not know why the communication is interrupted.

Code core logic writing

The core control logic is written in the esp8226 module, which circularly collects the temperature, and then publishes the temperature as a theme. The mobile phone can subscribe to the theme to view the boiler temperature in real time. In the cycle, there is a variable of the set temperature. If the collected temperature is higher than the set temperature, a theme with the switch theme on will be published, If the temperature is lower than the set temperature, a switch is published, the topic is closed, and each time you subscribe to the set topic, it is used to modify the set temperature variable.

esp01 controls the relay. You can subscribe to the switch topic every time, and then publish the current state of the switch as a topic every time.

I wrote this code logic at the beginning. The mobile phone only needs to publish and set the temperature theme, but it also needs people to adjust it with the mobile phone for a period of time, and it still can't realize automation. Later, I modified the code logic in esp8226, which is a little more complex.

The core logic of esp8226 is the same as above. The switch will be turned on every time the detected temperature is higher than the set temperature, but the switch will not be turned off immediately if the temperature is lower than the set temperature. Instead, wait for the detected temperature to be lower than the set temperature minus a variable, and then issue a topic of switch off. This is to solve the problem that the detection temperature jumps repeatedly at the set temperature threshold, resulting in the switch being turned on and off repeatedly in a short time. Here, a subtraction variable is introduced, which I call the temperature step. There is a problem here. If the boiler keeps heating up, even if the circulating pump is always started, the boiler temperature will not be lower than the set temperature (the temperature of the return pipe has been higher than the set temperature), then the circulating pump will be always on. Therefore, I introduce the second variable: the maximum start-up time. I start a timer after each start-up, If the timer time exceeds the maximum starting time, the circulating pump will be shut down no matter whether the temperature at this time is lower than the set temperature, and the set temperature will be increased. The increased temperature is the temperature step plus the current temperature. Here, the automatic adjustment of the set temperature (rising direction) is realized. There is another problem: when the furnace coal is burned out, the temperature gradually decreases, the detected temperature will certainly be far lower than the set temperature, and the circulating pump will never start. So here I introduce the third variable (callback detection time). When the esp8226 is powered on and started, start a timer. If the timing time is equal to the callback detection time, adjust the set temperature to the current temperature for automatic temperature callback. Assuming that the callback detection time is 30 minutes, even if the set temperature is higher than the detection temperature, It will also start the circulating pump in 30 minutes and realize a closed loop with the remaining logic, so as to realize the set temperature and automatic adjustment up and down. Here, I also added a variable minimum temperature. If the current temperature is lower than the minimum temperature, the circulating pump will not be started even if the current temperature is higher than the set temperature, which is used when coal is not burned. This prevents the circulating pump from starting every 30 minutes at any time, and the minimum temperature can be set to be higher than the ambient temperature.

Here, the temperature, temperature step, maximum startup time, callback detection time and minimum temperature can be set through the mobile terminal. I asked esp8226 to subscribe to these topics to set these variables.

esp8226 Code:

from machine import Pin,reset
import onewire
from ds18x20 import DS18X20
import time
import tm1637
from umqtt.simple import MQTTClient

def main():
    client_id = "esp_temperature"
    mserver = '192.168.0.99'
    #mserver = '192.168.3.200'
    #mserver = 'mq.tongxinmao.com'

    tm = tm1637.TM1637(clk=Pin(14), dio=Pin(12))
    ow=onewire.OneWire(Pin(4))
    d = DS18X20(ow)
    rom = d.scan()

    def sub_callback(topic, msg):
        # print((topic, msg))
        nonlocal setTemperature
        nonlocal lowTemperature
        nonlocal startTime
        nonlocal scanTime
        nonlocal step

        nonlocal startTimeTemp
        nonlocal scanTimeTemp
        nonlocal switchStatus

        data = int(msg.decode())
        if topic == b'setTemperature':
            setTemperature = data
        elif topic == b"setLowTemperature":
            lowTemperature = data
        elif topic == b"setStartTime":
            startTime = data
            startTimeTemp = startTime

        elif topic == b"setScanTime":
            scanTime = data*60
            scanTimeTemp = scanTime

        elif topic == b"setStep":
            step = data
        elif topic == b"switchWell":
            switchStatus = data
        else:
            print("error")

    def publishInfo():
        nonlocal client
        client.publish("setTemperatureR",str(setTemperature),retain=True)
        client.publish("setLowTemperatureR",str(lowTemperature),retain=True)
        client.publish("setStartTimeR",str(startTime),retain=True)
        client.publish("setScanTimeR",str(int(scanTime/60)),retain=True)
        client.publish("setStepR",str(step),retain=True)

    client = MQTTClient(client_id, mserver, 0)
    client.set_callback(sub_callback)
    client.connect()
    client.subscribe(b'setTemperature')
    client.subscribe(b'setLowTemperature')
    client.subscribe(b'setStartTime')
    client.subscribe(b'setScanTime')
    client.subscribe(b"setStep")
    client.subscribe(b"switchWell")

    showSet = True
    setTemperature = 40
    lowTemperature = 40
    startTime = 120 #Start time
    scanTime = 1800 #30 Minutes
    step = 7

    switchStatus = 0 # 0 means off and 1 means on

    startTimeTemp = startTime
    scanTimeTemp = scanTime

    while True:
        try:
            d.convert_temp()
            # Display temperature and set temperature
            nowTemperature = d.read_temp(rom[0])
            if showSet:
                tm.temperature(int(setTemperature))
            else:
                tm.number(int(nowTemperature*10))

            if int(nowTemperature) >= setTemperature and (not switchStatus) and int(nowTemperature) > lowTemperature:#Start above set temperature
                client.publish("switch",'1',retain=True)
                startTimeTemp = startTime

            if (int(nowTemperature) <= setTemperature - step) and switchStatus:
                client.publish("switch",'0',retain=True)

            if startTimeTemp <= 0: #If the time exceeds 3 minutes, it will stop automatically and increase the set temperature
                client.publish("switch",'0',retain=True)
                setTemperature = int(nowTemperature + step)
                startTimeTemp = startTime

            if switchStatus:
                startTimeTemp -= 1

            client.check_msg()
            client.publish("temperature",str(round(nowTemperature,2)),retain=True)
            publishInfo()
            
            if scanTimeTemp <= 0:
                setTemperature = int(nowTemperature - step) #Callback cooling
                scanTimeTemp = scanTime
            scanTimeTemp -= 1 

        except Exception as e:
            reset()

        time.sleep(1)
        showSet = not showSet


Code in esp01:

from machine import Pin
from umqtt.simple import MQTTClient
import time

def main():
    def sub_callback(topic, msg):
        nonlocal client
        nonlocal pin
        """
        Receive subscription message callback
        """
        if msg == b'0':
            pin.off()
        else:
            pin.on()
        client.publish("switchWell",str(pin.value()),retain=True)

    client_id = "switch_id"
    mserver = '192.168.0.99'
    #mserver = 'mq.tongxinmao.com'        
    pin = Pin(0,Pin.OUT)

    client = MQTTClient(client_id, mserver, 0)
    client.set_callback(sub_callback)
    client.connect()
    client.subscribe(b'switch')
    while True:
        client.check_msg()
        client.publish("switchStatus",str(pin.value()),retain=True)

5. Client monitoring and adjustment software

1. Mobile terminal:

MQTT Dash:

IoTMQTTPanel:

I still recommend IoTMQTTPanel on mobile phones, because it is convenient to publish the configuration of a set of panels to another mobile phone. You only need to publish a topic, and then the receiver can publish the whole panel by subscribing to a topic with the same name. MQTT Dash also has this function, but it will get stuck after publishing. I don't know why.

2. Computer side:

On the computer side, I don't know what software is easy to use, so I simply wrote a monitoring software with PyQt5 without adjustment function. Because the equipment was not very stable at that time, I was monitoring the running state all the time.

6. Postscript

At present, the whole thing has been running stably for two weeks, and no one needs to adjust it anymore. It took me a long time to solve all the problems, especially the LmacRxBlk:1 error report, which took me a long time. It is still difficult to do something useful from scratch, because some problems can only be exposed through the actual environment. For example, the resistance value changes after the pull-up resistance heats up. I haven't mentioned many details, such as burning firmware, 3d modeling shell, mosquitto service deployment on raspberry pie, port forwarding. There are too many contents to be repeated, so I can only briefly describe the main contents and logic.

Added by s_ff_da_b_ff on Wed, 26 Jan 2022 17:16:17 +0200