Отдельные уставки на каждый контур. Управляем и насосом тоже

This commit is contained in:
ftc
2025-12-14 15:38:49 +03:00
parent 14552403d3
commit 8f35d368e6
3 changed files with 42 additions and 21 deletions
+18 -16
View File
@@ -6,31 +6,33 @@
"contours": [
{
"sensor": "/devices/workroom_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A1"
"control": "/devices/wb-gpio/controls/EXT1_R3A6"
},
{
"sensor": "/devices/bathroom_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A2"
},
{
"sensor": "/devices/entrance_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A3"
},
{
"sensor": "/devices/corridor_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A4"
},
{
"sensor": "/devices/techroom_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A5"
},
{
"sensor": "/devices/entrance_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A1"
},
{
"sensor": "/devices/corridor_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A2"
},
{
"sensor": "/devices/techroom_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A4"
},
{
"sensor": "/devices/kitchen_weather/controls/t",
"control": "/devices/wb-gpio/controls/EXT1_R3A6"
"control": "/devices/wb-gpio/controls/EXT1_R3A3"
}
],
"target_temperature": 21.0,
"hysteresis": 0.5,
"boiler_exhaust_t": "/devices/wb-w1/controls/28-000000860adf",
"boiler_control": "/devices/wb-gpio/controls/EXT1_R3A8"
}
"pump_control": "/devices/wb-gpio/controls/EXT1_R3A8",
"boiler_control": "/devices/wb-gpio/controls/EXT1_R3A7"
}
+7 -1
View File
@@ -8,10 +8,12 @@ class Contour:
value_time = 0
state = None
state_change_time = 0
target_value = None
def __init__(self, config, logger):
self.sensor_topic = config['sensor']
self.out_topic = config['control']
self.target_topic = config['target']
self.logger = logger
def update(self, value):
@@ -29,4 +31,8 @@ class Contour:
if (self.state is None) or (time.time() - self.state_change_time > self.CHANGE_FREQ):
self.state = state_value
self.logger.info("Contour " + self.sensor_topic + " changed state to " + str(self.state))
def update_target(self, target_value):
self.target_value = target_value
+17 -4
View File
@@ -43,7 +43,7 @@ logger = logging.getLogger(__name__)
def load_config():
"""Load configuration from file"""
global config, contours, target_temp, boiler_control, hysteresis
global config, contours, target_temp, boiler_control, hysteresis, pump_control
try:
with open(CONFIG_FILE, 'r') as f:
config = json.load(f)
@@ -52,6 +52,7 @@ def load_config():
target_temp = float(config.get('target_temperature'))
hysteresis = float(config.get('hysteresis'))
boiler_control = config.get('boiler_control')
pump_control = config.get('pump_control')
if (boiler_control is None):
logger.error("Boiler control not configured")
exit(1)
@@ -74,6 +75,7 @@ def on_connect(client, userdata, flags, rc):
# Subscribe to all temperature sensor topics
for k in contours:
client.subscribe(k.sensor_topic)
client.subscribe(k.target_topic)
logger.info(f"Subscribed to: {k.sensor_topic}")
# and boiler exhaust topic
client.subscribe(config.get('boiler_exhaust_t'))
@@ -89,6 +91,10 @@ def on_message(client, userdata, msg):
temperature = float(msg.payload.decode('utf-8'))
k.update(temperature)
logger.debug(f"Updated {k.sensor_topic}: {temperature}°C")
if (k.target_topic == msg.topic):
temperature = float(msg.payload.decode('utf-8'))
k.update_target(temperature)
logger.debug(f"Updated target {k.target_topic}: {temperature}°C")
if msg.topic == config.get('boiler_exhaust_t'):
boiler_exhaust_t = float(msg.payload.decode('utf-8'))
logger.debug(f"Updated boiler exhaust: {boiler_exhaust_t}°C")
@@ -106,12 +112,14 @@ def check_temperatures():
# check boiler exhaust, turn off if too big
if (boiler_exhaust_t > BOILER_EXHAUST_LIMIT):
logger.error("Boiler exhaust overheat")
# will open all contours (to force coolant circulation)
# will open all contours (to force coolant circulation),
# turn on the pump
# and turn off the boiler of course
for c in contours:
# valves are normally-opened, so 0 means "open"
mqtt_client.publish(c.out_topic, "0", retain=True)
mqtt_client.publish(boiler_control, "0", retain=True)
mqtt_client.publish(pump_control, "1", retain=True)
return
#
sum_t = 0
@@ -137,10 +145,13 @@ def check_temperatures():
# sensor is offline
if contour_t is None:
contour_t = sum_t / count_t
if contour_t < target_temp - hysteresis:
target_t = target_temp
if not c.target_value is None:
target_t = c.target_value
if contour_t < target_t - hysteresis:
# should turn on contour
c.check_state(True)
if contour_t > target_temp + hysteresis:
if contour_t > target_t + hysteresis:
# should turn off contour
c.check_state(False)
if c.state:
@@ -161,8 +172,10 @@ def check_temperatures():
if any_opened and time.time() - any_opened_start > BOILER_TURN_ON_AFTER:
mqtt_client.publish(boiler_control, "1", retain=True)
mqtt_client.publish(pump_control, "1", retain=True)
else:
mqtt_client.publish(boiler_control, "0", retain=True)
mqtt_client.publish(pump_control, "0", retain=True)
def main_cycle():
"""Main 5-second cycle"""