【Python】如何寫一個鍋爐溫控系統

来源:https://www.cnblogs.com/1234567FENG/archive/2022/06/14/16371182.html
-Advertisement-
Play Games

1.前言 冬天很冷,買了一個鍋爐,需要迴圈泵的。簡單來說就是鍋爐水熱了之後迴圈泵自動開啟,然後將熱水輸送走,送到暖 氣,熱水抽走,涼水進入鍋爐,溫度降低,迴圈泵關閉,等待下一次水燒熱。因為需要取暖的房子距離燒鍋爐的地方比較遠,所以需要迴圈 泵,如果距離近的話水燒熱後利用熱水上流冷水迴流的原理會自動完 ...


1.前言

冬天很冷,買了一個鍋爐,需要迴圈泵的。簡單來說就是鍋爐水熱了之後迴圈泵自動開啟,然後將熱水輸送走,送到暖

氣,熱水抽走,涼水進入鍋爐,溫度降低,迴圈泵關閉,等待下一次水燒熱。因為需要取暖的房子距離燒鍋爐的地方比較遠,所以需要迴圈

泵,如果距離近的話水燒熱後利用熱水上流冷水迴流的原理會自動完成迴圈。當然目前市場上有這種利用溫度自動控制迴圈泵開啟關閉的設

備:

在這裡插入圖片描述

原理就是有一個熱敏電阻探頭(帶有磁鐵吸附,可以吸附到鍋爐壁上),然後一個繼電器控制的。當溫度達到設定的值後,繼電器開啟,循

環泵啟動,迴圈過後鍋爐壁溫度下降,繼電器關閉,迴圈泵關閉。

迴圈泵:

在這裡插入圖片描述

由於我家的迴圈泵功率較大,小繼電器啟動幾次就燒壞了,所以中間又接入了一層交流接觸器(我的老父親加的)。

這種市面上的設備可以大致解決水迴圈的問題,但是也有一些細節問題解決不了,例如:當迴流管水溫度也達到設定的溫度值後,迴圈泵就

會一直開啟狀態,這時候就需要手動去調節旋鈕溫度(調高),讓迴圈泵停下來(大功率迴圈泵很耗電)。又如 當爐子內部煤漸漸燒結束後

(東北話叫澇了),鍋爐溫度達不到設定值,這個時候就需要降低旋鈕,讓迴圈泵啟動,讓這些煤產生的餘溫不浪費掉。

由於以上的不足,就需要有人隔幾個小時去調節旋鈕。這部分工作都是我老父親在做,所以我想做一個自動的東西降低一下老父親的工作

量。

2.項目結構

我最初的構思是通過手機可以遠程調節溫度,這樣至少不用手動去調節旋鈕了,我半夜起來在被窩裡用手機調節一下就可以了。基於最初的

構思設計的結構:

在這裡插入圖片描述

3.硬體搭建

esp01模塊+繼電器模塊,220v轉5v模塊 + 插排 = 聯網插座

esp8226 + 溫度感測器 + 數位管 = 實時溫度檢測顯示聯網模塊

我的控制系統都寫在 esp8226中。

溫度感測器探頭製作:要驅動ds18b20感測器,需要在數據匯流排(DQ)與 VDD 引腳之間加入一個4.7k歐姆的電阻(上拉電阻),這個是必須

有的,用一個鐵紐扣包裹起來,裡面放了兩個小塊的釹磁鐵,最後用哥倆好膠水灌滿,這樣就形成了一個溫度感測器探頭,可以吸附在鍋爐

壁上:

在這裡插入圖片描述

這一步我犯了一個錯誤,將ds18b20感測器和上拉電阻都放入到探頭裡面,測溫的時候發現溫度升高以後溫度感測器讀取溫度失敗,是因為

溫度升高導致電阻阻值增大。後來我將其電阻放到尾部就解決了這個問題。

封裝後的探頭:

在這裡插入圖片描述

esp8226 + 數位管模塊:

在這裡插入圖片描述

殼子是我用3D印表機列印的,裡面放著esp8226模塊。

4.軟體編寫

固件

esp8226 和 esp01 我都是燒錄的micropython固件。
在這裡插入圖片描述

通信

通信開始我想的是用socket實現,簡單弄個HTTP協議進行通信,但是手機上這樣控制是比較麻煩的,沒有好用的軟體,我還要做個web界

面,另外socket會阻塞線程。

後來我發現了MQTT這種協議,這是一種針對物聯網的硬體網路通信協議,可以應對高延遲的網路環境。簡單介紹一下MQTT協議,首先需

要一個服務端(也有叫代{過}{濾}理伺服器的,運行在電腦上,這裡我運行在樹莓派上),然後你的所有物聯網硬體設備(如esp8226)都是客

戶端,物聯網硬體設備(客戶端)之間不會直接進行通信,它們都是與服務端直接進行通信,硬體設備之間如果需要進行通信是需要發佈或

者訂閱主題的。例如:如果硬體A 和硬體B 之間需要進行通信,那麼首先它們都需要連接到 服務端,然後 A 發佈一個名為topic的主題,如果

硬體B要接受A的信息就需要訂閱 topic這個主題,這樣就實現了 A —> B 的通信,那麼反向通信也是一個原理,B 發佈主題,A來訂閱。這個

協議還有一個優勢,可以一個主題多個客戶端去訂閱,這樣就能實現多端通信。mqtt協議通信中每個客戶端不知道其它客戶端的存在,他們

都是與服務端進行直接通信。
在這裡插入圖片描述

mqtt協議在micropython固件(我不知道安信可預設固件是不是也有)通信有一個很大的問題:LmacRxBlk:1報錯。例如,如果你在開始的時

候訂閱了一個主題,然後你使用非阻塞的方法check_msg()通過回調函數處理 訂閱的主題消息,這個時候如果你訂閱的主題發佈的次數超過

你 check_msg()的次數,那麼就會在micropython固件底層報一個錯誤 LmacRxBlk:1,然後通信中斷,簡單來說就是你訂閱一個主題後進入

事件迴圈,來不及處理訂閱主題的消息,就會導致這個錯誤。這個錯誤官方解釋是tcp buffer資源沒有釋放導致的,因為esp8226可用資源非

常有限,但是在mqtt通信中我不可能每次迴圈後都去釋放連接,然後每次都重新建立連接,並且這個報錯噁心的地方在於,try except 是捕

獲不到的,那麼對於處理這個錯誤只能通過設計上來解決了,也就是一開始就保證其訂閱的主題發佈的間隔遠小於其迴圈的間隔,保證每次

都能及時的處理訂閱的消息。這個問題我解決了很久,因為try except 捕獲不到,並且不常出現,無法定位,完全不知道為什麼通信會中

斷。

代碼核心邏輯編寫

最核心的控制邏輯我都寫在esp8226模塊中,迴圈採集溫度,然後將溫度作為一個主題發佈出來,手機可以訂閱主題就可以實時查看鍋爐溫

度了,在迴圈中有一個設定溫度的變數 ,如果採集的溫度高於 設定溫度 那麼就發佈一個 開關主題開啟的主題,如果溫度低於 設定溫度,那

麽就發佈一個 開關主題關閉,並且每次訂閱 設置主題,用於修改設定溫度變數。

esp01 控制繼電器,每次訂閱 開關主題 就可以了,然後每次再把 開關當前狀態 作為一個主題發佈出來。

這個代碼邏輯最開始我是這樣寫的,手機上只需要發佈設置溫度主題就可以了,但是也是需要人一段時間用手機去調節一次,還是不能實現自動化,後來我又修改的 esp8226 中的代碼邏輯,複雜了一些。
在這裡插入圖片描述

esp8226 核心邏輯還是和上述一樣,每次檢測溫度高於設定溫度後還會開啟開關,但是啟動後檢測到溫度低於設定溫度不會立刻關閉開關,

而是等待檢測溫度低於設定溫度減去一個變數再發佈一個開關關閉的主題。這是為瞭解決 檢測溫度在設定溫度臨界反覆跳變,從而導致開關

在短時間內反覆的開啟關閉,這裡引入了一個減去變數,我將其叫做溫度步長 。這裡就有一個問題,如果鍋爐一直在升溫,那麼就算迴圈泵

一直開啟 ,鍋爐溫度也不會低於設定溫度(迴流管溫度已經高於設定溫度了),那麼迴圈泵就會處於一直開啟狀態,所以這裡我引入了第二

個變數:啟動最大時長,每次啟動後我開啟一個計時器,如果計時器時間超過 啟動最大時長,那麼無論此時的溫度是否低於設定溫度,都會

關閉迴圈泵,並且將設定溫度提高,提高溫度為溫度步長加當前溫度,這裡就實現了 自動調節 設定溫度的(升高方向)。還有一個問題:

當爐子煤燃燒殆盡的時候,溫度逐漸降低,檢測到的溫度肯定會遠低於設定溫度,迴圈泵就永遠不會開啟了。所以這裡我引入了第三個變數

(回調檢測時間),當esp8226 上電啟動時,啟動一個計時器,如果計時時間 等於回調檢測時間,那麼將設定溫度 調節到當前溫度,用於

設定溫度 自動回調,假設回調檢測時間 為 30分鐘,那麼即使設定溫度 高於 檢測溫度,也會實現30分鐘一啟動迴圈泵,和剩餘邏輯實現一

個閉環,這樣就能實現 設定溫度,上下自動調節。這裡我還加入了一個變數最低溫度,如果當前溫度低於最低溫度,那麼就算 當前溫度高

於設定溫度 也不會啟動迴圈泵,用於沒燒煤炭的時候,這樣就防止了無論什麼時候都30分鐘啟動一次迴圈泵,最低溫度 設置成高於環境溫

度一些就可以了。

這裡 設定溫度,溫度步長,啟動最大時長,回調檢測時間,最低溫度,都可以通過手機端進行設置,我讓esp8226訂閱這些主題用於設置這

些變數。

esp8226代碼:

Python學習交流Q群:906715085###
 複製代碼 隱藏代碼
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("錯誤")

    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 #啟動時間
    scanTime = 1800 #30分鐘
    step = 7

    switchStatus = 0 # 0表示關閉,1表示開啟

    startTimeTemp = startTime
    scanTimeTemp = scanTime

    while True:
        try:
            d.convert_temp()
            # 顯示溫度和設定溫度
            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:#高於設定溫度啟動
                client.publish("switch",'1',retain=True)
                startTimeTemp = startTime

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

            if startTimeTemp <= 0: #如果時間超過3分鐘,自動停止,並提高設定溫度
                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) #回調降溫
                scanTimeTemp = scanTime
            scanTimeTemp -= 1 

        except Exception as e:
            reset()

        time.sleep(1)
        showSet = not showSet

 

在這裡插入圖片描述

esp01中代碼:

Python學習交流Q群:906715085###
 複製代碼 隱藏代碼
from machine import Pin
from umqtt.simple import MQTTClient
import time

def main():
    def sub_callback(topic, msg):
        nonlocal client
        nonlocal pin
        """
        收到訂閱消息回調
        """
        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.客戶端監控調節軟體

1.手機端:

MQTT Dash:

在這裡插入圖片描述

IoTMQTTPanel:

在這裡插入圖片描述

手機上我還是推薦IoTMQTTPanel,因為將一套面板的配置發佈到另一臺手機很方便,只需要發佈一個主題,然後接收端訂閱一個同名主題

就可以把整個面板發佈過去。MQTT Dash 也具有這個功能,但是發佈過去後會卡死,不知道為什麼。

2.電腦端:

電腦端我還不知道有什麼好用的軟體,所以我用 PyQt5 簡單寫了一個監控的軟體,沒有調節功能,因為當時設備還不是很穩定,所以我一直

在監控運行狀態。

6.後記

目前,整個東西已經穩定運行二周了,再也不需要人進行調節了。我反反覆復弄了挺長時間,才把所有問題都解決,特別是那個

LmacRxBlk:1報錯,花費了我很長時間。從零開始做一個能實際有用的東西還是挺困難的,因為有些問題只能通過實際的環境才能暴露出

來,例如上拉電阻升溫後導致阻值變化。還有很多細節我沒提及,例如燒錄固件,3d建模外殼,mosquitto服務在樹莓派上部署,埠轉發,

內容太多不便贅述,只能把主要內容和邏輯進行簡單敘述。

在這裡插入圖片描述


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • blind watermark 盲水印技術實現,這裡主要引用網上三種java實現的效果測試和研究。可以將文字隱藏在圖片中,通過提取還原水印,實現版本保護效果。 開源代碼: https://gitee.com/chejiangyi/shuiyin/tree/master ...
  • Practical usage of cpp reference and move semantic 在優化重構一部分老代碼時,實際使用 c++ 的 reference 與 move semantic 遇到了若幹問題,在此記錄。 Aggregation 首先,數據的設計並不複雜,只有一個類,成員變數 ...
  • C++函數重載的原理 一、函數重載概述 1.1 為什麼要有函數重載 在實際的開發中,有時候我們需要實現幾個功能類似的函數,只是有些細節不同。例如希望交換兩個變數的值,但是這兩個變數可能有多種類型:int、char、double、bool等。在C語言中,程式員往往需要分別設計出多個不同名的函數,但是在 ...
  • 前言 哈嘍,大家好。有沒有誰跟我一樣喜歡老照片的朋友,老照片總是讓人感覺有一種情懷,可能這就是懷念吧。有一次無意中看到 了很久很久以前的照片都是黑白的,當時很想給照片添加點顏色,但是不知道怎麼搞。今天,我終於發現了怎麼去解決這個問 題,想了想,我決定得把這個分享給大家… 今天我們分享用NoGAN的圖 ...
  • 1 什麼是hash衝突 我們知道HashMap底層是由數組+鏈表/紅黑樹構成的,當我們通過put(key, value)向hashmap中添加元素時,需要通過散列函數確定元素究竟應該放置在數組中的哪個位置,當不同的元素被放置在了數據的同一個位置時,後放入的元素會以鏈表的形式,插在前一個元素的尾部,這 ...
  • 一個工作8年的粉絲私信了我一個問題。 他說這個問題是去阿裡面試的時候被問到的,自己查了很多資料也沒搞明白,希望我幫他解答。 問題是: “Mysql為什麼使用B+Tree作為索引結構” 關於這個問題,看看普通人和高手的回答。 普通人: B+數它的特征就是相對B數來說他的這個非葉子節點不存數據,所有的數 ...
  • 前言 最近有沒有想要買股票和基金的小伙伴,今天我要教大家一個神奇的東西,如何去計算平均值。沒有人不喜歡錢吧… 用Python繪製出股價的5日均線和20日均線。眾所周知,5日均線是短線交易的生死線,而20日均線是中長線趨勢的分水嶺。因此,基於這兩 條均線,可以設計出一些簡單的交易策略。 下麵是我練習的 ...
  • 1、無限極往上獲取平臺類目樹信息 數據結構:商品類目id《category_id,商品類目父id《parent_id 數據需求:根據傳入最低層類目id,獲取所有上級類目信息(包含自己) 代碼如下: 1 // 無限極往上獲取平臺類目樹信息 2 public function platformCateg ...
一周排行
    -Advertisement-
    Play Games
  • 概述:本文代碼示例演示瞭如何在WPF中使用LiveCharts庫創建動態條形圖。通過創建數據模型、ViewModel和在XAML中使用`CartesianChart`控制項,你可以輕鬆實現圖表的數據綁定和動態更新。我將通過清晰的步驟指南包括詳細的中文註釋,幫助你快速理解並應用這一功能。 先上效果: 在 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • 概述:本示例演示了在WPF應用程式中實現多語言支持的詳細步驟。通過資源字典和數據綁定,以及使用語言管理器類,應用程式能夠在運行時動態切換語言。這種方法使得多語言支持更加靈活,便於維護,同時提供清晰的代碼結構。 在WPF中實現多語言的一種常見方法是使用資源字典和數據綁定。以下是一個詳細的步驟和示例源代 ...
  • 描述(做一個簡單的記錄): 事件(event)的本質是一個委托;(聲明一個事件: public event TestDelegate eventTest;) 委托(delegate)可以理解為一個符合某種簽名的方法類型;比如:TestDelegate委托的返回數據類型為string,參數為 int和 ...
  • 1、AOT適合場景 Aot適合工具類型的項目使用,優點禁止反編 ,第一次啟動快,業務型項目或者反射多的項目不適合用AOT AOT更新記錄: 實實在在經過實踐的AOT ORM 5.1.4.117 +支持AOT 5.1.4.123 +支持CodeFirst和非同步方法 5.1.4.129-preview1 ...
  • 總說周知,UWP 是運行在沙盒裡面的,所有許可權都有嚴格限制,和沙盒外交互也需要特殊的通道,所以從根本杜絕了 UWP 毒瘤的存在。但是實際上 UWP 只是一個應用模型,本身是沒有什麼許可權管理的,許可權管理全靠 App Container 沙盒控制,如果我們脫離了這個沙盒,UWP 就會放飛自我了。那麼有沒... ...
  • 目錄條款17:讓介面容易被正確使用,不易被誤用(Make interfaces easy to use correctly and hard to use incorrectly)限制類型和值規定能做和不能做的事提供行為一致的介面條款19:設計class猶如設計type(Treat class de ...
  • title: 從零開始:Django項目的創建與配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 後端開發 tags: Django WebDev Python ORM Security Deployment Op ...
  • 1、BOM對象 BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 1.1、window對象 視窗方法 // BOM Browser object model 瀏覽器對象模型 // js中最大的一個對象.整個瀏覽器視窗出現的所有東西都 ...