#
import os
from machine import I2C,Pin,RTC,Timer # RTC built-in
from eeprom_i2c import EEPROM,T24C512
import sh1106 # oled display Treiber
import time
from time import sleep
import onewire # fuer 1-wire
import ds18x20 # fuer 1-wire temp
import network
import ntptime # ntp PTBtime
import ftplib
#
monat=
[„“,“Jan“,“Feb“,“Mar“,“Apr“,“Mai“,“Jun“,“Jul“,“Aug“,“Sep“,“Okt“,“Nov“,“Dez
„]
definition und setup von System-Konstanten
const_kessel_is_off = 25.0 # wenn kaelter als ..
var_mixer_is_closed=False # zu bei HotWater
const_aussen_limit_summer=18.0
const_aussen_min_cold=8.0 # Hzg wieder an
const_T_aussen_avg=6 # no. of average readings
const_sensor_count=3
const_eeprom_dir = „/eeprom/“ # directory of ext memory
var_eeprom_ok = False # eeprom operational
const_daytime_start=5 # begin der warm phase early
const_daytime_stop=22 # begin of cold phase
var_is_daytime=True # hot day phase
var_current_time=“ # current time as str
const_T_offset_gen=0.0 # offset of T_sollw
const_T_offset_night=-2.0 # in daily cold phase
var_display_on=True
const_display_on_start=8 # 10 Uhr an
const_display_on_stop=23 # 22 Uhr aus
var_display_loop = 1 # partial display counter
const_display_loop = 6 # partial display num
var_is_summer = False
const_steilheit=0.39 # Hzg Steilheit
const_room_temp=20.0 # first guess
const_linear_range=4.0 # linear control range
const_motor_time=2.0 # move x longer than diff
var_ssid = „BEHAKU“
var_password = „dasisteinkeyderrockt“
var_Wifi_on=False # status WLan
const_ntp_host = „ptbtime2.ptb.de“
var_timeframe_ok = False # rtc time about correct n/ok
var_log_filename=““ # name of daily logfile
var_once_daily=True # do it only once daily
const_sleeptime = 0.2 # Sleeptime in seconds per perm loop
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 2
var_ftp_dir = ‚2023‘ # /home/** dir on ftp server
ESP32 pins for line power switches
PwrRelay1_enable=Pin(26,Pin.OUT)
PwrRelay2_enable=Pin(25,Pin.OUT)
PwrRelay1_enable.value(0)
PwrRelay2_enable.value(0)
#
frontpanel blue indicator LED
blueLED=Pin(27,Pin.OUT) # „1“ eq. off
blueLED.value(1) # off
#
pointer fuer OLED display SW
ds=0
display=0
#
Zeile mit logfile Werten
logtextline = “
var_current_time = “ # as str
#
init temperature variables
Tvalue_new = [] # list of new 18×20 readings
Tvalue_kessel = 0
Tvalue_sollw = 0
Tvalue_vorl = 0
Tvalue_aussen = 0
Tvalue_diff = 0
Tvalue_aussen_list = [10.5,10.5,10.5,10.5,10.5,10.5] # init
motor_time = 0.0 # motor activity time
scheduler: flags and timings
ntp_flag = False
tim_count_ntp_max = 15000 # 4h
tim_count_ntp = tim_count_ntp_max
meas_flag = False
tim_count_meas_max = 60 # 1min
tim_count_meas = tim_count_meas_max
display_flag = False
tim_count_display_max = 20 # 3x /min
tim_count_display = tim_count_display_max
eep_flag = False
tim_count_eep_max = 603 # 11min
tim_count_eep = tim_count_eep_max
control_flag = False
tim_count_control_max = 300 # 5min
tim_count_control = tim_count_control_max
ftp_flag = False
tim_count_ftp_max = 1203 # 20min
tim_count_ftp = tim_count_ftp_max
blink_flag = False
tim_count_blink = 1 # 1sec
#
def handler_0(tim_0):
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 3
task scheduler with 1 sec loop
global tim_count_ntp
global tim_count_meas
global tim_count_ftp
global tim_count_eep
global tim_count_display
global tim_count_control
global ntp_flag
global meas_flag
global ftp_flag
global display_flag
global eep_flag
global control_flag
global blink_flag
tim_count_ntp -=1 # decrement
if tim_count_ntp == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
ntp_flag = True
tim_count_ntp = tim_count_ntp_max
tim_count_meas -=1 # decrement
if tim_count_meas == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
meas_flag = True
tim_count_meas = tim_count_meas_max
tim_count_display -=1 # decrement
if tim_count_display == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
display_flag = True
tim_count_display = tim_count_display_max
tim_count_eep -=1 # decrement
if tim_count_eep == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
eep_flag = True
tim_count_eep = tim_count_eep_max
tim_count_control -=1 # decrement
if tim_count_control == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
control_flag = True
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 4
tim_count_control = tim_count_control_max
tim_count_ftp -=1 # decrement
if tim_count_ftp == 0:
blueLED.value(0)
sleep(0.2)
blueLED.value(1)
ftp_flag = True
tim_count_ftp = tim_count_ftp_max
blink_flag = True
#
tim0 = Timer(0)
tim0.init(period=1000,mode=Timer.PERIODIC,callback=handler_0)
#
def init_sys():
global ds
global display
global var_eeprom_ok
initialisieren OLED sh1106 display
i2c = I2C(0, scl=Pin(22), sda = Pin(21),freq=100000)
display = sh1106.SH1106_I2C(128,64,i2c,None,0x3c,0)
display.sleep(False)
display.contrast(60)
showtext1 = “ ESP32 Mixer „
showtext2 = “ …starting.“
display.fill(0)
display.text(showtext1,0,10)
display.text(showtext2,0,20)
display.show()
#
initialisieren serielle Temp.-Sensoren
ow=onewire.OneWire(Pin(33))
ow.reset()
ds=ds18x20.DS18X20(ow)
init eeprom log Speicher 128k -> boot.py
eep = EEPROM(I2C(0,scl=Pin(22),sda=Pin(21)),T24C512)
sleep(0.1)
try:
os.mount(eep,’/eeprom‘)
var_eeprom_ok = True
except:
var_eeprom_ok = False
#
if var_eeprom_ok == True:
print(„eeprom mem ok: „, os.listdir(„/eeprom“))
return
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 5
#
def meas_temps():
aktualisieren von measurements, average, update globals
global Tvalue_aussen_list
global Tvalue_aussen
global Tvalue_kessel
global Tvalue_vorl
global Tvalue_new
read temp sensors data set at every timer flag
Tvalue_new = read_ds18x20(Tvalue_new)
build average over last … readings of T_aussen temp
Tvalue_aussen_tmp = Tvalue_new[2]
print(‚Taussen_raw: ‚,Tvalue_aussen_tmp)
Tvalue_aussen_list.append(Tvalue_aussen_tmp)
del Tvalue_aussen_list[0] # pop the oldest
len_tmp = len(Tvalue_aussen_list)
Tvalue_aussen = sum(Tvalue_aussen_list)/float(len_tmp)
Tvalue_aussen = round(Tvalue_aussen,2)
read the temp of FB vorlauf water and kessel
Tvalue_vorl = round(Tvalue_new[1],2)
Tvalue_kessel = round(Tvalue_new[0],2)
#
return
#
def find_daytime():
define display on/off period from hours field in .datetime()
global var_display_on
global var_is_daytime
global display
global var_ftp_dir
if (RTC().datetime()[4] > const_display_on_start) and \
(RTC().datetime()[4] <= const_display_on_stop):
var_display_on=True
display.sleep(False)
else:
var_display_on = False # normally False
display.sleep(True)
#
define warm daytime or cold nighttime period
if (RTC().datetime()[4] > const_daytime_start) and \
(RTC().datetime()[4] < const_daytime_stop):
var_is_daytime = True
else:
var_is_daytime = False
#
define the current year for ftp storage dir
var_ftp_dir = str(RTC().datetime()[0])
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 6
return
#
def find_filename():
define new logfile name for every new day
global var_log_filename
month_tmp = monat[RTC().datetime()[1]]
date_tmp = str(RTC().datetime()[2])
new_filename=“logfile-„+month_tmp+date_tmp+“.txt“
var_log_filename = new_filename # global var
return new_filename
#
def calc_Tsoll(T_aussen):
calculation of FB Vorlauf target
always add const_T_offset_gen
new_temp = const_steilheit * (const_room_temp – T_aussen) +
const_room_temp
new_temp = new_temp + const_T_offset_gen
new_temp = round(new_temp,2)
return new_temp
#
#
def display_oled(linecnt):
collect data and display on oled display 15char/line
dynamic 8 values in 4 steps shifted by 2 lines
global display
global var_display_on
global var_current_time
if var_display_on :
textline1 = „*ESP32 „+var_current_time
textline2 = „T-aussen “ +str(Tvalue_aussen)
textline3 = „T-kessel “ +str(Tvalue_kessel)
textline4 = „T-vorl “ +str(Tvalue_vorl)
textline5 = „T-sollw “ +str(Tvalue_sollw)
textline6 = „motor-tm “ +str(motor_time)
textline7 = „daytime “ +str(var_is_daytime)
textline8 = „systime “ +var_current_time
textline9 = „Wifi on “ +str(var_Wifi_on)
textline10 = „RTC ok “ +str(var_timeframe_ok)
#
if linecnt == 1:
showtext1 = textline1
showtext2 = textline2
showtext3 = textline3
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 7
showtext4 = textline4
showtext5 = textline5
showtext6 = textline6
elif linecnt == 2:
showtext1 = textline3
showtext2 = textline4
showtext3 = textline5
showtext4 = textline6
showtext5 = textline7
showtext6 = textline8
elif linecnt == 3:
showtext1 = textline5
showtext2 = textline6
showtext3 = textline7
showtext4 = textline8
showtext5 = textline9
showtext6 = textline10
elif linecnt == 4:
showtext1 = textline7
showtext2 = textline8
showtext3 = textline9
showtext4 = textline10
showtext5 = textline1
showtext6 = textline2
elif linecnt == 5:
showtext1 = textline3
showtext2 = textline4
showtext3 = textline5
showtext4 = textline6
showtext5 = textline7
showtext6 = textline8
#
display.sleep(False)
display.fill(0)
display.text(showtext1,0,0)
display.text(showtext2,0,10)
display.text(showtext3,0,20)
display.text(showtext4,0,30)
display.text(showtext5,0,40)
display.text(showtext6,0,50)
display.show()
else:
display.sleep(True)
return
#
#
def store_logdata():
form the log data line and store on eeprom
global logtextline
global var_is_daytime
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 8
global var_eeprom_ok
global var_current_time
logtextline = var_current_time
logtextline = logtextline +“;“+str(Tvalue_aussen)
logtextline = logtextline +“;“+str(Tvalue_kessel)
logtextline = logtextline +“;“+str(Tvalue_vorl)
logtextline = logtextline +“;“+str(Tvalue_sollw)
diff_tmp = round(Tvalue_diff,2)
logtextline = logtextline +“;“+str(diff_tmp)
logtextline = logtextline +“;“+str(round(motor_time,2))
if var_is_daytime:
day_tmp = „day „
else:
day_tmp = „night“
logtextline = logtextline +“;“+day_tmp
logtextline = logtextline + „\n“
print(„log: „,logtextline)
if var_eeprom_ok:
try:
filename_tmp = const_eeprom_dir + find_filename()
with open(filename_tmp,“a“) as file:
file.write(logtextline)
print(‚eeprom mem: log data stored‘)
except:
print(„I/O error on file write“)
return
#
def read_ds18x20(readings):
subroutine to measure 18×20 sensors and return list of values
global var_Wifi_on
global ds
readings.clear()
roms = ds.scan()
cnt_sens = len(roms)
sleep(0.9)
print(„found“, str(cnt_sens),“sensors.“)
try:
ds.convert_temp()
sleep(3.0)
except:
print(„found“,str(cnt_sens),“sensors – error in DS18x20 convert
access“)
for rom in roms:
ds18x20_temp = ds.read_temp(rom)
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 9
readings.append(ds18x20_temp)
#
return readings
#
def connect_wifi():
connect built-in WLAN to local access point
global var_Wifi_on
global blueLED
station = network.WLAN(network.STA_IF)
station.active(True)
if station.isconnected() == True:
print(„Wifi already connected.“)
blueLED.value(0) # blink 1x on
sleep(0.4)
blueLED.value(1)
else:
station.connect(var_ssid,var_password)
while station.isconnected() == False:
pass
print(„Wifi connection successful.“)
#
blueLED.value(0) # blink 2x on
sleep(0.3)
blueLED.value(1) # off
if station.isconnected() == True:
var_Wifi_on = True
return
#
def update_ntp_time():
global var_timeframe_ok
global var_Wifi_on
if var_Wifi_on:
ntptime.host = const_ntp_host
MEZ_sec = ntptime.time() +3600 # always winter time
print(‚Wifi on: ntp service: ‚,MEZ_sec)
rtc = RTC()
(year,month,day,hours,minutes,seconds,weekday,yearday) =
time.localtime(MEZ_sec)
rtc.datetime((year,month,day,0,hours,minutes,seconds,0))
rtc time newer than Oct 2023
if time.time() > 750262800:
var_timeframe_ok = True
else:
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 10
var_timeframe_ok = False
else:
print(„Time/RTC: set error – no Wifi.“)
return
#
def move_mixer(mtime):
activate the relais to move the mixer valve
do nothing if time < 1 sec
global PwrRelay1_enable
global PwrRelay2_enable
if (mtime > 1.0) :
PwrRelay1_enable.value(1)
sleep(mtime)
PwrRelay1_enable.value(0)
elif (mtime < -1.0) :
mtime = abs(mtime)
PwrRelay2_enable.value(1)
sleep(mtime)
PwrRelay2_enable.value(0)
return
#
def control_func():
compute movem. and control the 3way valve
global Tvalue_sollw
global Tvalue_kessel
global Tvalue_aussen
global Tvalue_vorl
global Tvalue_diff
global motor_time
find_daytime()
Tvalue_sollw = calc_Tsoll(Tvalue_aussen)
if not var_is_daytime:
Tvalue_sollw = Tvalue_sollw + const_T_offset_night
Tvalue_diff = Tvalue_sollw – Tvalue_vorl
limit active diff temp max to +/- linear range
if (Tvalue_diff > const_linear_range) :
Tvalue_diff = const_linear_range
elif (Tvalue_diff < -const_linear_range) :
Tvalue_diff = -const_linear_range
command mixer motor movement + -> open, – -> close
motor_time = round((const_motor_time * Tvalue_diff),2)
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 11
move_mixer(motor_time)
Tvalue_kessel = round((Tvalue_kessel),2)
Tvalue_aussen = round((Tvalue_aussen),2)
Tvalue_vorl = round((Tvalue_vorl),2)
Tvalue_diff = round(Tvalue_diff,2)
print(„actual time: „,var_current_time)
print(„1: T-aussen „, Tvalue_aussen)
print(„2: T-Kessel „, Tvalue_kessel)
print(„3: T-FB-Vorl.“, Tvalue_vorl)
print(„4: T-FB-Soll.“, Tvalue_sollw)
print(„5. Tval-diff: „, Tvalue_diff)
print(„6: Motor-time: „, motor_time)
return
#
def ftp_store():
#
global var_log_filename
global var_ftp_dir
session=ftplib.FTP
(„192.168.3.215″,21,“heizung“,“Lambergstrasse4060!“,““)
file_tmp=const_eeprom_dir + var_log_filename
print(‚ftp file to transfer: ‚,file_tmp)
ftpcmd = „/home/“+var_ftp_dir
session.cwd(ftpcmd)
file=open(file_tmp,“rb“)
ftpcmd=“STOR „+ var_log_filename
print(‚ftp target file: ‚,var_log_filename)
session.storbinary(ftpcmd,file)
file.close()
session.close()
print(„…tried ftp upload to leonding@nas“)
date_limit=time.time() – 150000 # 41h old
dir_len=len(os.listdir(‚/eeprom‘))
loop=dir_len -1
print(‚files loop: ‚, str(loop))
while loop >= 0:
file1=os.listdir(‚/eeprom‘)[loop]
filename1=’/eeprom/’+str(file1)
print(‚filename1: ‚,filename1)
filedate_raw=os.stat(filename1)[7]
if (filedate_raw < date_limit) and timeframe_ok == True:
os.remove(filename1)
print(’now deleted: ‚,filename1)
loop -=1
C:\Users\manfr\Desktop\ESP32-DEV\main-Okt19-Leo.py 12
return
#
main
#
init_sys() # i2c,display,eeprom
#
connect_wifi() # to local Wifi BEHAKU
#
update_ntp_time()
#
find_daytime()
#
while True: # continuous loop
if meas_flag:
meas_temps()
meas_flag = False
if control_flag:
find_daytime()
control_func()
control_flag = False
if eep_flag:
var_log_filename = find_filename()
store_logdata()
eep_flag = False
if display_flag:
var_current_time = str(time.localtime()[3])+“:“ \
+str(time.localtime()[4])+“:“+str(time.localtime()[5])
display_oled(var_display_loop)
var_display_loop +=1 # increm. screen loop
if var_display_loop == const_display_loop:
var_display_loop = 1
display_flag = False
if ftp_flag:
ftp_store()
ftp_flag = False
if blink_flag:
blueLED.value(0) # on
sleep(0.1)
blueLED.value(1)
blink_flag = False
sleep(const_sleeptime)
#
#
######################end