HW
V kotelně mám automatický kotel dakon na uhlí/pelety. Ten je přes čerpadlo připojen na nátopnou nádrž.
V nátopné nádrži mám 27 litrový výměník na ohřev pitné vody.
V létě natápím 6kW dražickou patronou pro ohřev pitné vody.
Nádrž je napojena na topný okruh přes čerpadlo a směšovací ventil.
Aktuální stav
Natápění si řidí kotel (teplota výstupní vody, teplota spalin, posun paliva, řízení přívodu vzduchu) - teplotu, na kterou kotel topí je možno řídit externě přes 0-10V
Letní natápění nádrže provádím na patroně ručně (v časech spínání HDO)
směšovací ventil není připojený
radiátory jsou osazeny termoregulačními hlavicemi s centrálním řízením
topný okruh má čerpadlo s automatickou detekcí stavu okruhu - od toho se odvíjí čerpaný objem
nátopná nádrž je připravená na další zdroje - solární/termický ohřev - tepelné čerpadlo
celý systém má kopici objímek na čidla teploty (osazeno analogovými budíky) a je tam i čidlo na tlak
Je patrné, že možnosti co a jak řídit je nespočet. Otopnou soustavu jsem si stavěl svépomocí. Aktuálně bezproblémově funguje, ale rád bych postupně zvýšil uživatelský komfort a pomocí ekvitermního řízení optimalizoval spotřebu
Prvním krokem bylo vymyslet nějaký malý projekt a konečně v kotelně RPi osadit.
Projekt č. 1 - hlídání množství uhlí v násypce kotle
Dlouhodobě jsem řešil možnosti hlídání hladiny uhlí v násypce. První co mě napadlo byl ultrazvukový senzor vzdálenosti, ale kvůli prašnosti prostředí by to bylo neschůdné. Pak mě napadlo násypku vážit, ale to by bylo technicky špatně proveditelné. Nakonec mě napadlo snímat otáčky šnekového posuvníku, který dopravuje palivo z násypky do hořáku.
Taktika byla jednoduchá - zjistit počet otáček do vyprázdnění násypky (v tomto stavu aktuálně jsem) a následně zaslat zprávu na telegram když bude obsah v násepce 15% a po doplnění násypky vynulovat čítač.
Oprášil jsem starou RPi 1B a dal se do práce.
Nejdřív jsem počítal s halovou sondou a snímáním rotujícího magnetu na hřídeli - nebyl jsem však spokojen s přesností, tak jsem nakonec použil mikrospínač a na hřídel jsem dal kousek železa, který na něj při otáčení mačká (hřídel je snadno dostupná pod plastovým krytem, do kterého jsem spínač zadělal). Zároveň jsem použil čidlo BMP180 na snímání venkovní teploty přes I2C.
Pro kódování jsem použil python, a každou hodinu odsypávám "log" datum/čas teplota počet otáček bokem.
Hodnotu teploty snímám vždy s "otáčkou" - obě hodnoty sypu do souboru do /dev/shm (ramdisk) ať neždímám SD kartu.
Resetovat čítač otáček a získávat aktuální status mohu přes telegram příkazy /status a /reset
Co dál - rád bych postupně dodělal notifikaci na doplnění násypky a pak bych chtěl řešit nějakou jednoduchou vizualizaci - statický web na rpi s vykreslováním grafů přes javascript (mám doma nějaké extra old androidí tablety, které by mohly fungovat jako stavové displeje+resetovač). Postupně dodám fotky a finální zdroják. Pokud máte nějaké nápady/návrhy, rád si je vyslechnu!!! Níže přikládám, aktuální zdroják - neni to nikterak úchvatné, ale funguje to
Kód: Vybrat vše
#!/usr/bin/env python
from time import sleep
import RPi.GPIO as GPIO
import smbus
from ctypes import c_short
import requests
import telepot
from telepot.loop import MessageLoop
def send_msg(text):
token = "<TELEGRAM_TOKEN>"
chat_id = "<CHAT_ID>"
url_req = "https://api.telegram.org/bot" + token + "/sendMessage" + "?chat_id=" + chat_id + "&text=" + text
results = requests.get(url_req)
def handle(msg):
chat_id = msg['chat']['id']
command = msg['text']
print(command)
if command == '/reset':
bot.sendMessage(chat_id, "nuluji citac")
f = open(OTACKY, "w")
f.write("0")
f.close()
elif command == '/status':
fo = open(OTACKY, "r")
ot=str(fo.read())
ft = open(TEPLOTA, "r")
te=str(ft.read())
bot.sendMessage(chat_id,"teplota: "+te+" otacky: "+ ot)
def convertToString(data):
# Simple function to convert binary data into
# a string
return str((data[1] + (256 * data[0])) / 1.2)
def getShort(data, index):
# return two bytes from data as a signed 16-bit value
return c_short((data[index] << 8) + data[index + 1]).value
def getUshort(data, index):
# return two bytes from data as an unsigned 16-bit value
return (data[index] << 8) + data[index + 1]
def readBmp180Id(addr=DEVICE):
# Chip ID Register Address
REG_ID = 0xD0
(chip_id, chip_version) = bus.read_i2c_block_data(addr, REG_ID, 2)
return (chip_id, chip_version)
def readBmp180(addr=0x77):
# Register Addresses
REG_CALIB = 0xAA
REG_MEAS = 0xF4
REG_MSB = 0xF6
REG_LSB = 0xF7
# Control Register Address
CRV_TEMP = 0x2E
CRV_PRES = 0x34
# Oversample setting
OVERSAMPLE = 3 # 0 - 3
# Read calibration data
# Read calibration data from EEPROM
cal = bus.read_i2c_block_data(addr, REG_CALIB, 22)
# Convert byte data to word values
AC1 = getShort(cal, 0)
AC2 = getShort(cal, 2)
AC3 = getShort(cal, 4)
AC4 = getUshort(cal, 6)
AC5 = getUshort(cal, 8)
AC6 = getUshort(cal, 10)
B1 = getShort(cal, 12)
B2 = getShort(cal, 14)
MB = getShort(cal, 16)
MC = getShort(cal, 18)
MD = getShort(cal, 20)
# Read temperature
bus.write_byte_data(addr, REG_MEAS, CRV_TEMP)
sleep(0.005)
(msb, lsb) = bus.read_i2c_block_data(addr, REG_MSB, 2)
UT = (msb << 8) + lsb
# Read pressure
bus.write_byte_data(addr, REG_MEAS, CRV_PRES + (OVERSAMPLE << 6))
sleep(0.04)
(msb, lsb, xsb) = bus.read_i2c_block_data(addr, REG_MSB, 3)
UP = ((msb << 16) + (lsb << 8) + xsb) >> (8 - OVERSAMPLE)
# Refine temperature
X1 = ((UT - AC6) * AC5) >> 15
X2 = (MC << 11) / (X1 + MD)
B5 = X1 + X2
temperature = int(B5 + 8) >> 4
temperature = temperature / 10.0
# Refine pressure
B6 = B5 - 4000
B62 = int(B6 * B6) >> 12
X1 = (B2 * B62) >> 11
X2 = int(AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((AC1 * 4 + X3) << OVERSAMPLE) + 2) >> 2
X1 = int(AC3 * B6) >> 13
X2 = (B1 * B62) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (AC4 * (X3 + 32768)) >> 15
B7 = (UP - B3) * (50000 >> OVERSAMPLE)
P = (B7 * 2) / B4
X1 = (int(P) >> 8) * (int(P) >> 8)
X1 = (X1 * 3038) >> 16
X2 = int(-7357 * P) >> 16
pressure = int(P + ((X1 + X2 + 3791) >> 4))
#pressure = float(pressure / 100.0)
altitude = 44330.0 * (1.0 - pow(pressure / 101325.0, (1.0/5.255)))
altitude = round(altitude,2)
return (temperature,pressure,altitude)
send_msg("startuji kotelnika")
bot = telepot.Bot(<TELEGRAM_TOKEN>)
MessageLoop(bot, handle).run_as_thread()
GPIO.setmode(GPIO.BCM)
INPUT_PIN = 22
GPIO.setup(INPUT_PIN, GPIO.IN)
OTOCENI=GPIO.input(INPUT_PIN)
OTACKY="/dev/shm/otacky"
TEPLOTA="/dev/shm/teplota"
f = open(OTACKY, "w")
f.write("0")
f.close()
DEVICE = 0x77 # Default device I2C address
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
temp, pressure, altitude = readBmp180()
f = open(TEPLOTA, "w")
f.write(str(temp))
f.close()
while True:
if (GPIO.input(INPUT_PIN) == True):
OTOCENI=True
else:
if (OTOCENI == True):
f = open(OTACKY, "r")
o=str(int(f.read())+1)
f = open(OTACKY, "w")
f.write(o)
f.close()
temp, pressure, altitude = readBmp180()
f = open(TEPLOTA, "w")
f.write(str(temp))
f.close()
print(str(temp))
print(o)
OTOCENI = False
sleep(0.3)