Boiler Control Software

Boiler control

This software includes a control program on the master Uno, a program to operate the servo on the slave Uno and a supervision and control program running on a Raspberry Pi (for example) written in Python.

Uno software

The software below is to run on the master Uno Written in C/C++ or whatever the Arduino IDE language is. It monitors the temperatures measured by the sensors and sends the data on request by UDP. It operates the servo controlling the boiler temperature (via the slave Uno) according to timings stored on SD and overrides these if requested by commands sent over UDP. It also can save the updated control timings on the SD card.

// boiler_MASTER_19b
//12.3.23
//by Julian Rogers
// v.19b replaced v.17a
//develop getting times!
//access SD to save hi and lo times
// #17a is currently running
// still getting errors on flo & ret conversions but not at these values!
//Master Arduino
//D4 = used by Ethernet Shield, SD card
//D10= SPI (Ethernet Shield, SD card)
//D11= SPI
//D12= SPI
//D13= SPI
//D6 = oneWire
//d7 = manual/auto switch
//A0 = manual temp pot
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Wire.h>
#include <SD.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "Sodaq_DS3231.h"
#include "Adafruit_LiquidCrystal.h"
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 107);
unsigned int localPort = 8888; 
// Setup a oneWire instance to communicate with any OneWire device, pin 6
OneWire oneWire(6);
// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);
// Connect via i2c, default address #0 (A0-A2 not jumpered)
Adafruit_LiquidCrystal lcd(0);
// An EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
byte deviceCount = 0;    // number of 1-Wire devices detected
//  hold temperature values of three sensors, ext, flo, ret
bool p = true; // swiches output to LCD display
unsigned int tim;        // current time of day in miniutes
unsigned int loStart; //= 570;  //9:30
unsigned int hiStart; //= 1080; //18:00
// flags
bool hiMode;
bool loMode;
bool manMode = false;
bool remMode = false;
byte Amode;
byte Bmode;
byte Cmode;
byte lo = 55;  // values passed to servo corresponding to high and low
byte hi = 160; // boiler settings.
File myFile;
//=====================================================================
void setup() {
sensors.begin();
lcd.begin(16,2);
Wire.begin();
rtc.begin();
Serial.begin(9600);
// start the Ethernet, UDP, Serial and I2C:
Ethernet.begin(mac,ip);
Udp.begin(localPort);
SD.begin(4);
// open file and get values -----------------------
char histartString[5];
char lostartString[5];
myFile = SD.open("histart.txt");
if (myFile) {
//Serial.println("histart.txt:");
// read from the file until there's nothing else in it:
byte index = 0;
while (myFile.available()) {
histartString[index] = myFile.read();
index++;
//Serial.println("reading histart..");
}
// close the file:
myFile.close();
}
hiStart = atoi(histartString);
//Serial.println(hiStart);
//delay(2000);
// open file and get values
myFile = SD.open("lostart.txt");
if (myFile) {
//Serial.println("lostart.txt:");
// read from the file until there's nothing else in it:
byte index = 0;
while (myFile.available()) {
lostartString[index] = myFile.read();
index++;
//Serial.println("reading losart..");
}
// close the file:
myFile.close();
}
loStart = atoi(lostartString);
//Serial.println(loStart);
//delay(2000);
// pin7 is for toggle switch
pinMode(7, INPUT_PULLUP);
deviceCount = sensors.getDeviceCount();
//set up flags
DateTime now = rtc.now();
int tim = 60 * now.hour() + now.minute();
if(tim >= loStart && tim < hiStart){
loMode = true;
hiMode = false;
}
else{
loMode = false;
hiMode = true;
}
}
//========================================================================
void loop() {
DateTime now = rtc.now();
tim = 60 * now.hour() + now.minute();
if(!digitalRead(7)){
int val = analogRead(0);
val = map(val, 0, 1023, 55, 160);
byte bval = byte(val);
Wire.beginTransmission(0x10);
Wire.write(bval);
Wire.endTransmission();
manMode = true;
}
else{
if(tim >= loStart && tim < hiStart && loMode){
Wire.beginTransmission(0x10);
Wire.write(lo);
Wire.endTransmission();
loMode = false;
hiMode = true;
manMode = false;
}
if((tim < loStart || tim >= hiStart) && hiMode){
Wire.beginTransmission(0x10);
Wire.write(hi);
Wire.endTransmission();
hiMode = false;
loMode = true;
manMode = false;
}
// reset at start of new day
if(tim < 1){
hiMode = true;
loMode = true;
}
}
// Send command to all the sensors for temperature conversion
sensors.requestTemperatures();
float flo = sensors.getTempCByIndex(0);
float ext = sensors.getTempCByIndex(1);
float ret = sensors.getTempCByIndex(2);
if(p){
lcd.setCursor(0,0);
lcd.print("Flow   ");
lcd.print(flo);
lcd.print(" C    ");
lcd.setCursor(0,1);
lcd.print("Return ");
lcd.print(ret);
lcd.print(" C ");
}
else{
lcd.setCursor(0,0);
lcd.print("Exterior  ");
lcd.print(ext);
lcd.print(" C");
lcd.setCursor(0,1);
lcd.print("                ");
}
p = !p;  
delay(2000);
//........................................................
// Here is where the progam checks to see if data is being sent
// and sends back status data
// if there's data available, read a packet  
int packetSize = Udp.parsePacket();
if(packetSize){
// read the packet into packetBufffer
char packetBuffer[10]; 
Udp.read(packetBuffer,10);   
//first send back data
char timstr[6];
char flostr[7];
char retstr[7];
char extstr[6];
char himodestr[5];
char lomodestr[5];
char manmodestr[5];
char lowVal[5], highVal[5];
itoa(tim, timstr, 10);
itoa(flo, flostr, 10);
itoa(ret, retstr, 10);
itoa(ext, extstr, 8);
itoa(hiMode, himodestr, 6);
itoa(loMode, lomodestr, 6);
itoa(manMode, manmodestr, 6);
itoa(hiStart, highVal, 10);
itoa(loStart, lowVal, 10);
//remembering "hiMode" is "false" when it is actually true! Same for loMode.
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(timstr);
Udp.write("x");
Udp.write(flostr);
Udp.write("x");
Udp.write(retstr);
Udp.write("x");
Udp.write(extstr);
Udp.write("x");
Udp.write(lomodestr);
Udp.write("x");
Udp.write(himodestr);
Udp.write("x");
Udp.write(manmodestr);
/*
// do I need to write back this stuff?
Udp.write("x");
Udp.write(packetBuffer[0]);
Udp.write("x");
Udp.write(packetBuffer[1]);
Udp.write("x");
Udp.write(packetBuffer[2]);
Udp.write("x");
Udp.write(packetBuffer[3]);
Udp.write("x");
Udp.write(packetBuffer[4]);
*/
//strings 7 and 8, now
char hitimstr[5], lotimstr[5];
itoa(hiStart, hitimstr, 10);
itoa(loStart, lotimstr, 10);
Udp.write("x");
Udp.write(hitimstr);
Udp.write("x");
Udp.write(lotimstr);
Serial.println(hiStart);
Serial.println(hitimstr); //huh?
Serial.println(lotimstr);
Udp.endPacket();
//.......................................
//now process received data
if(packetSize != 8){
char a = packetBuffer[0];
char b = packetBuffer[1];
char c = packetBuffer[2];
//Serial.print(a);
//Serial.print(" : ");
Amode = a - '0';
Bmode = b - '0';
Cmode = c - '0';
//Serial.println(Amode);
if(Amode){
Wire.beginTransmission(0x10);
Wire.write(hi);
Wire.endTransmission();
}
else if(Bmode){
Wire.beginTransmission(0x10);
Wire.write(lo);
Wire.endTransmission();
}
// effects a mode reset
else if(Cmode){
hiMode = true;
loMode = true;
}
}
//.....................................
if(packetSize == 8){
// read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
char lowVal[5], highVal[5];
highVal[0] = packetBuffer[0];
highVal[1] = packetBuffer[1];
highVal[2] = packetBuffer[2];
highVal[3] = packetBuffer[3];
highVal[4] = '\0';
lowVal[0] = packetBuffer[4];
lowVal[1] = packetBuffer[5];
lowVal[2] = packetBuffer[6];
lowVal[3] = packetBuffer[7];
lowVal[4] = '\0';
//now update values & save to SD
SD.remove("lostart.txt");    //first delete previous file
delay(200);
myFile = SD.open("lostart.txt", FILE_WRITE);
if (myFile) {
myFile.print(lowVal);
myFile.close();
}
SD.remove("histart.txt");    //first delete previous file
delay(200);
myFile = SD.open("histart.txt", FILE_WRITE);
if (myFile) {
myFile.print(highVal);
myFile.close();
}
// register new values
hiStart = atoi(highVal);
loStart = atoi(lowVal);
//reset
hiMode = true;
loMode = true;
}
//..............................................
} //end of UDP section
} //end of main loop
//========================================================================

The next program runs on the slave Uno. The master sends instructions via I2C. The slave cuts off power to the servo when it doesn’t need to move to prevent any chattering.

// boiler_slave5
// 19.2.23
// by JR
// uses mosfet to switch servo on/off
// to avoid any chatter
// tested 19.2.23 - no problems
// servo on 9
// IRF349 on 2
#include <Wire.h>
#include <Servo.h>
Servo myservo;
byte oldrcv = 0;
byte rcv = 85;  // mid value default
void setup() {
Wire.begin(0x10);
Wire.onReceive(rcvd);
//Wire.onRequest(snd);
myservo.attach(9);
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
}
void loop() {
// try this also?
// if(rcv < (oldrcv -2) || rcv > (oldrcv + 2)){
if(rcv != oldrcv){
digitalWrite(2, HIGH);
delay(100);
myservo.write(rcv);
delay(750);
digitalWrite(2, LOW);
oldrcv = rcv;
}
}
void rcvd(int numBytes) {
while(Wire.available()){
rcv = Wire.read();
}
}

Python program – control GUI

The program below, in Python, supervises the boiler temperature control Uno and the boiler timer Uno. I apologise for the poor quality of my programming! It does, at least, seem to work! Maybe I’ll get better with time. (Although since I have been programming for well over forty years, that, probably, ain’t going to happen!)

# GUI to control Feather timer/controller
# 19/3/23 
# by Julian Rogers
# master_controller_X12
# Incorporates master_controller_1 (2016-2017 and boiler controller9)
# Controls timer Arduino and Boiler temp Arduino via UDP
# 
# 
IP = "192.168.1.177" #remote ip address
IP_BOILER = "192.168.1.177"
IP_ROOM = "192.168.1.54"
IP_13amp = "192.168.1.91"
IP_ARD = "192.168.1.107"
DEST_PORT = 8888    #destination port
DEST_PORT_BOILER = 8888
DEST_PORT_ROOM = 2390
DEST_PORT_ARD = 8888
THIS_PORT = 5000     #port on this computer
BACKGROUND = "gray"
BUTTON_1 = "light yellow"       #buttons: advance, load, refresh
BUTTON_2 =  "cornflower blue"     #update buttons
from tkinter import *   #GUI
#import datetime
from datetime import datetime
import time
import socket           #UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Manual overrides. Amode sets boiler temp high, Bmode, low, Cmode resets hi or low to automatic
global Amode, Bmode, Cmode, old_response, count
global tm_int # Ard time in minutes
global flag # used in sequence evert 15 minutes
global over_ride   # flag used in ensuring boiler is high when water is being heated
global temp_hall, temp_room, kitchen_temp
global mod_on_flag  # modulation on / off flag
global set_modo_flag  # use modulation mode - like a thermostat
start_temp = "18" # modulation default temp
temp_hall = 0
temp_room = 0
kitchen_temp = 0
mod_on_flag = False
set_modo_flag = True  # start with modulation mode in operation
flag = True
Amode = 0
Bmode = 0
Cmode = 0
old_response = ""
count = 0
over_ride = False
#-------------------------------------------------------------
# create the root window
root = Tk()
# modify the window
root.title("CENTRAL HEATING CONTROL by Julian Rogers 2023")
root.configure(bg = BACKGROUND)
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
# create a frame
app = Frame(root)
app.configure(bg = BACKGROUND)
app.grid()
#----------------------------------------------------------------------
lbl_time = Label(app, text = "B Timer > ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time.grid(row = 2, column = 2, sticky = E)
#create labels for minutes and hours display
# This is a bodge for aesthetc reasons! Labels are unseen and just used to store values
# until I get round to a more efficient solution!
hour_lab = Label(app, text = "00", font = ("Arial", 4), fg = BACKGROUND, bg = BACKGROUND)
hour_lab.grid(row = 2, column = 3, sticky = E)
lbl_colon = Label(app, text = ":", font = ( "Arial", 4), fg = BACKGROUND, bg = BACKGROUND)
lbl_colon.grid(row = 2, column = 4, sticky = W)
mins_lab = Label(app, text = "00", font = ("Arial", 4), fg = BACKGROUND, bg = BACKGROUND)
mins_lab.grid(row = 2, column = 5, sticky = W)
time_but = Button(app, text = "00" + ":" + "00", font = ("Arial", 16), fg = "maroon", bg = BUTTON_2)
time_but.grid(row = 2, column = 3, sticky = W)
#----------------------------------------------------------
#blank row
blank_row = Label(app, text = "",  fg = "black", bg = BACKGROUND)
blank_row.grid(row = 7, column = 1)
#-------------------------------------------------------------------------------------
#heating and water label
lbl_heating = Label(app, text = "SYS. A ", font = ( "Arial ", 16), fg = "maroon", bg = BACKGROUND)
lbl_heating.grid(row = 2, column = 6, columnspan = 4, sticky = E)
# effectively create blank column
lbl_row = Label(app, text = "    ",  bg = BACKGROUND)
lbl_row.grid(row = 2, column = 11)  
lbl_water = Label(app, text = "SYS. B ", font = ( "Arial ", 16), fg = "maroon", bg = BACKGROUND)
lbl_water.grid(row = 2, column = 11, columnspan = 4, sticky = E)
#------------------------------------------------------------------------
# labels for heating and water on off times
lbl_time_on1 = Label(app, text = "On 1- ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time_on1.grid(row = 3, column = 6, sticky = E)
lbl_time_off1 = Label(app, text = "Off 1- ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time_off1.grid(row = 4, column = 6, sticky = E)
lbl_time_on2 = Label(app, text = "On 2- ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time_on2.grid(row = 5, column = 6, sticky = E)
lbl_time_off2 = Label(app, text = "Off 2- ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time_off2.grid(row = 6, column = 6, sticky = E)
lbl_advance_status = Label(app, text = "Advance ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_advance_status.grid(row = 5, column = 2, sticky = E)
#create a button to update on / off times on remote timer -------------------------------------------
def update_times():
lbl_feedback.config(text = "updating on / off times ... ")
#onoff_times = StringVar()
onoff_times = water_on1_hour_label.cget("text") + "," + water_on1_mins_label.cget("text") + "," +\
water_off1_hour_label.cget("text") + "," + water_off1_mins_label.cget("text") + "," +\
water_on2_hour_label.cget("text") + "," + water_on2_mins_label.cget("text") + "," +\
water_off2_hour_label.cget("text") + "," + water_off2_mins_label.cget("text") + "," +\
heat_on1_hour_label.cget("text") + "," + heat_on1_mins_label.cget("text") + "," +\
heat_off1_hour_label.cget("text") + "," + heat_off1_mins_label.cget("text") + "," +\
heat_on2_hour_label.cget("text") + "," + heat_on2_mins_label.cget("text") + "," +\
heat_off2_hour_label.cget("text") + "," + heat_off2_mins_label.cget("text") 
lbl_feedback_2.config(text = onoff_times)
sock.sendto(bytes(onoff_times, "utf-8") , (IP, DEST_PORT))
update_times_but = Button(app, text = "Load on/off", font = ("Arial", 16), fg = "black", bg = BUTTON_1, command = update_times)
update_times_but.grid(row = 8, column = 12, columnspan = 5, sticky = W)
#-------------------------------------------------------------------####
# labels to show heat on/off times
heat_on1_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_on1_hour_label.grid(row = 3, column = 7, sticky = E)
#colon label
lbl_colon2 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon2.grid(row = 3, column = 8)
heat_on1_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_on1_mins_label.grid(row = 3, column = 9, sticky = W)
heat_off1_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_off1_hour_label.grid(row = 4, column = 7, sticky = E)
#colon label
lbl_colon3 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon3.grid(row = 4, column = 8)
heat_off1_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_off1_mins_label.grid(row = 4, column = 9, sticky = W)
#----------------------------------------------------------------------------------------
heat_on2_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_on2_hour_label.grid(row = 5, column = 7, sticky = E)
#colon label
lbl_colon3 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon3.grid(row = 5, column = 8)
heat_on2_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_on2_mins_label.grid(row = 5, column = 9, sticky = W)
heat_off2_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_off2_hour_label.grid(row = 6, column = 7, sticky = E)
#colon label
lbl_colon4 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon4.grid(row = 6, column = 8)
heat_off2_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
heat_off2_mins_label.grid(row = 6, column = 9, sticky = W)
#------------------------------------------------------------------------
#advance buttons
heat_advance_but = Button(app, text = "N", font = ("Arial", 16), fg = "maroon", bg = BUTTON_1)
heat_advance_but.grid(row = 5, column = 3, columnspan = 6, sticky = W)
def heat_adv():
but_text = heat_advance_but.config('text')[-1]
if but_text == "Y":
but_text = "N"
else:
but_text = "Y"
heat_advance_but.config(text = but_text)
other_but = water_advance_but.config("text")[-1]
lbl_feedback_2.config(text = but_text + other_but)
sock.sendto(bytes(but_text + other_but, "utf-8") , (IP , DEST_PORT))
get_data_remote()
clear_feedback()
heat_advance_but.config(command = heat_adv)
water_advance_but = Button(app, text = "N", font = ("Arial", 16), fg = "maroon", bg = BUTTON_1)
water_advance_but.grid(row = 5, column = 4, columnspan = 6, sticky = W)
def water_adv():
but_text = water_advance_but.config('text')[-1]
if but_text == "Y":
but_text = "N"
else:
but_text = "Y"
water_advance_but.config(text = but_text)
other_but = heat_advance_but.config("text")[-1]
lbl_feedback_2.config(text = but_text + other_but)
sock.sendto(bytes(other_but + but_text, "utf-8") , (IP , DEST_PORT))
get_data_remote()
clear_feedback()
water_advance_but.config(command = water_adv)
#--------------------------------------------------------------------------------------
# labels to show water on/off times
water_on1_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_on1_hour_label.grid(row = 3, column = 12, sticky = E)
#colon label
lbl_colon4 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon4.grid(row = 3, column = 13)
water_on1_mins_label = Label(app, text = "00",  font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_on1_mins_label.grid(row = 3, column = 14, sticky = W)
water_off1_hour_label = Label(app, text = "00",  font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_off1_hour_label.grid(row = 4, column = 12, sticky = E)
#colon label
lbl_colon5 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon5.grid(row = 4, column = 13)
water_off1_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_off1_mins_label.grid(row = 4, column = 14, sticky = W)
#----------------------------------------------------------------------------------------
water_on2_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_on2_hour_label.grid(row = 5, column = 12, sticky = E)
#colon label
lbl_colon6 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon6.grid(row = 5, column = 13)
water_on2_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_on2_mins_label.grid(row = 5, column = 14, sticky = W)
water_off2_hour_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_off2_hour_label.grid(row = 6, column = 12, sticky = E)
#colon label
lbl_colon7 = Label(app, text = ":", font = ( "Arial", 16), fg = "red", bg = BACKGROUND)
lbl_colon7.grid(row = 6, column = 13)
water_off2_mins_label = Label(app, text = "00", font = ("Arial", 16), fg = "red", bg = BACKGROUND)
water_off2_mins_label.grid(row = 6, column = 14, sticky = W)
#---------------------------------------------------------------------------------
#create blank row in effect
blank_row2 = Label(app, text = " ",  bg = BACKGROUND)
blank_row2.grid(row = 9, column = 6)
#label to show switch status on remote timer
lbl_switch_status = Label(app, text = "Switch ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_switch_status.grid(row = 4, column = 2, sticky = E)
sw_heatstat_but = Button(app, text = "T", font = ("Arial", 16), fg = "maroon", bg = "grey")
sw_heatstat_but.grid(row = 4, column = 3, sticky = W)
sw_waterstat_but = Button(app, text = "T", font = ("Arial", 16), fg = "maroon", bg = "grey")
sw_waterstat_but.grid(row = 4, column = 4, sticky = W)
#-------------------------------------------------------------------------------------
#create blank row in effect
blank_row3 = Label(app, text = " ",  bg = BACKGROUND)
blank_row3.grid(row = 12, column = 6)
# labels to show remote temperature sensor values etc
lbl_temp_sensor1 = Label(app, text = "Temp > ", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_temp_sensor1.grid(row = 7, column = 1, columnspan = 4, sticky = W)
temp_sensor1_but = Button(app, text = "00.0", font = ("Arial bold", 16), fg = "red", bg = BACKGROUND)
temp_sensor1_but.grid(row = 7, column = 3, sticky = W)
#temp_sensor2_label = Label(app, text = "00.0", font = ("Arial bold", 16), fg = "red", bg = BACKGROUND)
#temp_sensor2_label.grid(row = 8, column = 3, sticky = W)
lbl_thermostat = Label(app, text = "Conventional Stat", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_thermostat.grid(row = 9, column = 2, columnspan = 3, sticky = W)
#option menu to ser thermostat value
var3 = StringVar(app)
var3.set("18") # initial value
thermostat_opt_men = OptionMenu(app,var3, "8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25")
thermostat_opt_men.config(font = ("Arial", 14), fg = "black", bg = BUTTON_1, width = 2)
thermostat_opt_men.grid(row = 10, column = 1, columnspan = 2, sticky = W)
#---------------------------------------------------------
#create a button to update thermostat setting
def update_thermo():
lbl_feedback.config(text = "updating stat setting...      ")
thermo_str = var3.get() + "0"
lbl_feedback_2.config(text = thermo_str)
sock.sendto(bytes(thermo_str, "utf-8") , (IP, DEST_PORT))
get_data_remote()
clear_feedback()
update_thermo_but = Button(app, text = "New Set", font = ("Arial", 16), fg = "black", bg = BUTTON_1, command = update_thermo)
update_thermo_but.grid(row = 10, column = 3, columnspan = 3, sticky = W)
#create blank row in effect
blank_row4 = Label(app, text = " ",  bg = BACKGROUND)
blank_row4.grid(row = 16, column = 2)
blank_row5 = Label(app, text = " ",  bg = BACKGROUND)
blank_row5.grid(row = 17, column = 2)
#--------------------------------------------------------------------------------------
# This, below, is what runs every 10 seconds to refresh the data on the screen and update the two Arduino
# Unos controlling the boiler etc.
def get_data_remote():
global Amode, Bmode, Cmode
# get system time from Pi
now = datetime.now()
systime = now.strftime("%H:%M:%S")
systime_but.config(text = systime)
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
#not on Feather version
#lbl_feedback.config(text = "Data from remote is...")
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(bytes("r", "utf-8") , (IP, DEST_PORT))
sock.settimeout(5)
response = sock.recv(100)
except socket.error:
lbl_feedback.config(text = "timed out!")
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
sock.close()
response = str(response, "utf-8")
#not pn Feater version
#lbl_feedback_2.config(text = response)
try:
tim, other_data1 = response.split("/")
except ValueError:
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
response = str(response, "utf-8")
tim, other_data1 = response.split("/")
on_offs, other_data2 = other_data1.split("T")
temp_sensor , other_data3 = other_data2.split("S")
switch_mode, other_data4 = other_data3.split("A")
advance_mode, thermo_setting = other_data4.split("t")
thermo_setting = thermo_setting[0:2]
thermostat_opt_men.config(var3.set(thermo_setting))
#lbl_feedback_2.config(text = on_offs)
tim_int = int(tim)
clock_hrs = tim_int // 60
clock_mins = tim_int % 60
if clock_hrs < 10:
clock_hrs_str = "0" + str(clock_hrs)
else:
clock_hrs_str = str(clock_hrs)
if clock_mins < 10:
clock_mins_str = "0" + str(clock_mins)
else:
clock_mins_str = str(clock_mins)
hour_lab.config(text = clock_hrs_str)         
mins_lab.config(text = clock_mins_str)
time_but.config(text = clock_hrs_str + ":" + clock_mins_str) 
a_status_int = int(advance_mode)
adv_status = ("N","Y")
h_adv_status = adv_status[a_status_int % 2]
w_adv_status = adv_status[a_status_int // 2]
s_mode_int = int(switch_mode)
sw_condition = ("T","O","C")
w_mode_str = sw_condition[s_mode_int // 3]
h_mode_str = sw_condition[s_mode_int % 3]
water_advance_but.config(text = w_adv_status)
heat_advance_but.config(text = h_adv_status)
sw_heatstat_but.config(text = h_mode_str)
sw_waterstat_but.config(text = w_mode_str)
won1_hrs,won1_mins,woff1_hrs,woff1_mins,won2_hrs,won2_mins,woff2_hrs,woff2_mins,\
hon1_hrs,hon1_mins,hoff1_hrs,hoff1_mins,hon2_hrs,hon2_mins,hoff2_hrs, hoff2_mins = on_offs.split(",",15)
heat_on1_hour_label.config(text = hon1_hrs)
heat_on1_mins_label.config(text = hon1_mins)
heat_off1_hour_label.config(text = hoff1_hrs)
heat_off1_mins_label.config(text = hoff1_mins)
heat_on2_hour_label.config(text = hon2_hrs)
heat_on2_mins_label.config(text = hon2_mins)
heat_off2_hour_label.config(text = hoff2_hrs)
heat_off2_mins_label.config(text = hoff2_mins)
water_on1_hour_label.config(text = won1_hrs)
water_on1_mins_label.config(text = won1_mins)
water_off1_hour_label.config(text = woff1_hrs)
water_off1_mins_label.config(text = woff1_mins)
water_on2_hour_label.config(text = won2_hrs)
water_on2_mins_label.config(text = won2_mins)
water_off2_hour_label.config(text = woff2_hrs)
water_off2_mins_label.config(text = woff2_mins)
temperature = float(temp_sensor)
temperature = temperature / 10
temp_sensor = str(temperature)
temp_sensor1_but.config(text = temp_sensor )
# determine whether boiler is actually on or off
# first is it timed to be on?
wonh1 = int(won1_hrs)
wonm1 = int(won1_mins)
wonm1 = wonh1 * 60 + wonm1
woffh1 = int(woff1_hrs)
woffm1 = int(woff1_mins)
woffm1 = woffh1 * 60 + woffm1
wonh2 = int(won2_hrs)
wonm2 = int(won2_mins)
wonm2 = wonh2 * 60 + wonm2
woffh2 = int(woff2_hrs)
woffm2 = int(woff2_mins)
woffm2 = woffh2 * 60 + woffm2
honh1 = int(hon1_hrs)
honm1 = int(hon1_mins)
honm1 = honh1 * 60 + honm1
hoffh1 = int(hoff1_hrs)
hoffm1 = int(hoff1_mins)
hoffm1 = hoffh1 * 60 + hoffm1
honh2 = int(hon2_hrs)
honm2 = int(hon2_mins)
honm2 = honh2 * 60 + honm2
hoffh2 = int(hoff2_hrs)
hoffm2 = int(hoff2_mins)
hoffm2 = hoffh2 * 60 + hoffm2
if (honm1 <= tim_int < hoffm1) or (honm2 <= tim_int < hoffm2):
heat = True
else:
heat = False
if (wonm1 <= tim_int < woffm1) or  (wonm2 <= tim_int < woffm2):
water = True
else:
water = False
# next what about advance status?    
if a_status_int == 1 or a_status_int == 3:
heat = not heat
if a_status_int == 2 or a_status_int == 3:
water = not water
# finally what about the over ride switches?
if w_mode_str == "O":
water = False
if w_mode_str == "C":
water = True
if h_mode_str == "O":
heat = False
if h_mode_str == "C":
heat = True
if heat and  temperature < float(thermo_setting):
bheat_but.config(bg = "orange red", fg = "orange red")
status_but2.config(text = " On ")
if heat and temperature >= float(thermo_setting):
bheat_but.config(bg = "sandy brown", fg = "sandy brown")
if not heat:
bheat_but.config(bg = "black", fg = "black")
status_but2.config(text = " Off ")
if water:
bwater_but.config(bg = "orange red", fg = "orange red")
else:
bwater_but.config(bg = "black", fg = "black")
# end of boiler on off question!
# See prvious version for day of the week and all that jazz - not used on this version
get_ard_data()
#---------------------------------------------------------------------------
def override() :
# overrides low setting if hot water needed
global over_ride, count
colour = bwater_but.config('bg')[-1]
testbut.config(text = colour)
if bwater_but.config('bg')[-1] == "orange red" and  status_but.config('text')[-1] == "low" :
modeA()
over_ride = True
feedbackbut.config(text = "Override on")
if over_ride == True and bwater_but.config('bg')[-1] == "black" :
over_ride = False
if count == 1:
feedbackbut.config(text = " XXXXX ")
else:
feedbackbut.config(text = " ----- ")
modeC()
#--------------------------------------------------------------------------------------------
# get data from boiler control Arduino
def get_ard_data():
global Amode, Bmode, Cmode, old_response, count, tm_int, flag
cmd = str(Amode) + str(Bmode) + str(Cmode) + str(modo.get())
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(bytes(cmd, "utf-8") , (IP_ARD, DEST_PORT_ARD))
sock.settimeout(5)
response = sock.recv(100)
except socket.error:
# not sure about this...
response = bytes("0x0x0x0x0x0x0x0", "utf-8")
response = str(response, "utf-8")
#lbl_feedback3.config(text = "Ard timed out!")
sock.close()
try:
response = str(response, "utf-8")
except TypeError:
# not sure about this too!
response = bytes("0x0x0x0x0x0x0x0", "utf-8")
response = str(response, "utf-8")
dataList = response.split("x")
#ext_but.config(text = str(dataList[3])) - already a string!
ext_but.config(text = (dataList[3]))
flo_but.config(text = (dataList[1]))
ret_but.config(text = (dataList[2]))
if dataList[4] == "1" :
status_but.config(text = "high")
elif dataList[5] == "1" :
status_but.config(text = "low")
else:
status_but.config(text = " ? ")
tm_int = int(dataList[0])
clock_hrs = tm_int // 60
clock_mins = tm_int % 60
if clock_hrs < 10:
clock_hrs_str = "0" + str(clock_hrs)
else:
clock_hrs_str = str(clock_hrs)
if clock_mins < 10:
clock_mins_str = "0" + str(clock_mins)
else:
clock_mins_str = str(clock_mins)
ardtime_but.config(text =clock_hrs_str  + ":" + clock_mins_str)
# clear yellow colour on reset button after 20 sec
count = count + 1
if count == 2:
modeC_but.config(bg = BUTTON_2)
count = 0
#get low on, low off times
try:
tim_lowon_int = int(dataList[8])
tim_lowoff_int = int(dataList[7])
tim_lowon_hr = tim_lowon_int // 60
tim_lowon_min = tim_lowon_int % 60
tim_lowoff_hr = tim_lowoff_int // 60
tim_lowoff_min = tim_lowoff_int % 60
if tim_lowoff_min < 10:
tim_lowoff_min_str = "0" + str(tim_lowoff_min)
else:
tim_lowoff_min_str = str(tim_lowoff_min)
if tim_lowon_min < 10:
tim_lowon_min_str = "0" + str(tim_lowoo_min)
else:
tim_lowon_min_str = str(tim_lowon_min)
except IndexError :
tim_lowon_hr = 0
tim_lowon_min_str  = "00"
tim_lowoff_hr = 0
tim_lowoff_min_str = "00"
lbl_low_ontime.config(text = str(tim_lowon_hr) + ":" + tim_lowon_min_str)
lbl_low_offtime.config(text = str(tim_lowoff_hr) + ":" + tim_lowoff_min_str)
# sequence kicks in every 15 minutes
if tm_int % 15 != 0 :
flag = True
if tm_int % 15 == 0 and flag == True :
flag = False
load_room_temps()
# override low setting if hot water needed    
override()
modulation()
#-----------------------------------------------------------------------------------------
def get_temp_rooms(ip, dest):
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(bytes("r", "utf-8") , (ip, dest))
sock.settimeout(5)
response = sock.recv(100)
except socket.error:
lbl_feedback.config(text = "timed out!")
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
sock.close()
response = str(response, "utf-8")
try:
tim, other_data1 = response.split("/")
except ValueError:
response = bytes("0/00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00T0S0A0t0", "utf-8")
response = str(response, "utf-8")
tim, other_data1 = response.split("/")
on_offs, other_data2 = other_data1.split("T")
temp_sensor , other_data3 = other_data2.split("S")
temperature = float(temp_sensor)
temperature = temperature / 10
return temperature
#-------------------------------------------------------------------------
def load_room_temps() :
# get temps
global temp_hall, temp_room, kitchen_temp
temp_hall = get_temp_rooms(IP_BOILER, DEST_PORT_BOILER)
temp_room = get_temp_rooms(IP_ROOM, DEST_PORT_ROOM)
kitchen_temp = get_temp_rooms(IP_13amp, DEST_PORT_ROOM)
# upload to screen
hall_but.config(text = str(temp_hall))
frm_but.config(text = str(temp_room))
kit_but.config(text = str(kitchen_temp))
#-----------------------------------------------------------------
def modulation() :
global temp_hall, temp_room, kitchen_temp, mod_on_flag, set_modo_flag
if set_modo_flag == True :
try:
testbut.config(text = hall_but.config('text')[-1])
except ValueError:
temp = 0
testbut.config(text = "ERR")
set_temp = int(modo.get()) # from option menu
if temp_hall > set_temp and mod_on_flag == False:
feedbackbut.config(text = "modo ON")
modeB()
mod_on_flag = True
if temp_hall <= set_temp and mod_on_flag == True: 
feedbackbut.config(text = "modo OFF")
modeC()
mod_on_flag = False
elif mod_on_flag == True :
feedbackbut.config(text = "modo OFF")
modeC()
mod_on_flag = False
#--------------------------------------------------------------------------
# option menues to set minutes and hours
var6 = StringVar(app)
var6.set("00") # initial value
hour_opt_men = OptionMenu(app,var6,"00","01","02","03","04","05","06","07","08","09","10",\
"11","12","13","14","15","16","17","18","19","20","21","22",\
"23")
hour_opt_men.config(font = ("Arial", 14), fg = "black", bg = BUTTON_2, width = 2)
hour_opt_men.grid(row = 10, column = 12, columnspan = 2, sticky = W)
# minutes only multiples of 5 as 60 options do not fit on the Pi screen!
var7 = StringVar(app)
var7.set("00") # initial value
min_opt_men = OptionMenu(app,var7,"00","05","10","15","20","25","30","35","40","45","50","55")
min_opt_men.config(font = ("Arial", 14), fg = "black", bg = BUTTON_2, width = 2)
min_opt_men.grid(row = 10, column = 14, columnspan = 2, sticky = W)
lbl_time_set = Label(app, text = "Time Set hh:mm", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_time_set.grid(row = 9, column = 12, columnspan = 6, sticky = W)
def upd_time():
mins_lab.config(text = var7.get())
hour_lab.config(text = var6.get())
time_but.config(text = var6.get() + ":" + var7.get())
def update_hon1():
heat_on1_hour_label.config(text = var6.get())
heat_on1_mins_label.config(text = var7.get())
def update_hoff1():
heat_off1_hour_label.config(text = var6.get())
heat_off1_mins_label.config(text = var7.get())
def update_hon2():
heat_on2_hour_label.config(text = var6.get())
heat_on2_mins_label.config(text = var7.get())
def update_hoff2():
heat_off2_hour_label.config(text = var6.get())
heat_off2_mins_label.config(text = var7.get())
def update_won1():
water_on1_hour_label.config(text = var6.get())
water_on1_mins_label.config(text = var7.get())
def update_woff1():
water_off1_hour_label.config(text = var6.get())
water_off1_mins_label.config(text = var7.get())
def update_won2():
water_on2_hour_label.config(text = var6.get())
water_on2_mins_label.config(text = var7.get())
def update_woff2():
water_off2_hour_label.config(text = var6.get())
water_off2_mins_label.config(text = var7.get())
#update heat times from time entry
update_hon1_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_hon1)
update_hon1_but.grid(row = 3, column = 10, columnspan = 1, sticky = W)
update_hoff1_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_hoff1)
update_hoff1_but.grid(row = 4, column = 10, columnspan = 1, sticky = W)
update_hon2_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_hon2)
update_hon2_but.grid(row = 5, column = 10, columnspan = 1, sticky = W)
update_hoff2_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_hoff2)
update_hoff2_but.grid(row = 6, column = 10, columnspan = 1, sticky = W)
#update water times from time entry
update_won1_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_won1)
update_won1_but.grid(row = 3, column = 15, columnspan = 1, sticky = W)
update_woff1_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_woff1)
update_woff1_but.grid(row = 4, column = 15, columnspan = 1, sticky = W)
update_won2_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_won2)
update_won2_but.grid(row = 5, column = 15, columnspan = 1, sticky = W)
update_woff2_but = Button(app, text = "U", font = ("Arial", 16), fg = "black", bg = BUTTON_2, command = update_woff2)
update_woff2_but.grid(row = 6, column = 15, columnspan = 1, sticky = W)
#---------------------------------------------------------------------------------------
# feedback label 1
lbl_feedback = Label(app, text = "", font = ( "Arial Bold", 13), fg = "black", bg = BACKGROUND)
lbl_feedback.grid(row = 10, column = 6, columnspan = 6, sticky = W)
# feedback label 2
lbl_feedback_2 = Label(app, text = "", font = ( "Arial Bold", 8), fg = "black", bg = BACKGROUND)
lbl_feedback_2.grid(row = 13, column = 6, columnspan = 13, sticky = W)
# feedback label 3
lbl_feedback_3 = Label(app, text = "", font = ( "Arial Bold", 13), fg = "black", bg = BACKGROUND)
lbl_feedback_3.grid(row = 2, column = 4, columnspan = 6, sticky = W)
#---------------------------------------------------------------------------------------
# clear feedback
def clear_feedback():
lbl_feedback.config(text = "")
lbl_feedback_2.config(text = "")
lbl_feedback_3.config(text = "")
#---------------------------------------------------------------------------------------
# reset button
def reset_timer():
lbl_feedback.config(text = "")
lbl_feedback_2.config(text = "")
lbl_feedback_3.config(text = "")
sock.sendto(bytes("xxxx", "utf-8") , (IP, DEST_PORT))
get_data_remote()
#reset not implemented in feather controller at this time    
#reset_but = Button(app, text = "reset", font = ("Arial", 16), fg = "black", bg = "grey", command = reset_timer)
#reset_but.grid(row = 13, column = 3, columnspan = 2, sticky = E)
#---------------------------------------------------------------------------------------
# boiler on "buttons)
bheat_but = Button(app, font = ("Arial Bold", 16), bg = "grey", fg = "red", text = "X")
bheat_but.grid(row = 2, column = 10, sticky = W)
bwater_but = Button(app, font = ("Arial Bold", 16), bg = "grey", fg = "red", text = "X")
bwater_but.grid(row = 2, column = 15, sticky = W)
#----------------------------------------------------------------------------------------
# controller select button 
cont_select_but = Button(app, text = "Boiler", font = ("Arial", 16), fg = "red", bg = BUTTON_1)
cont_select_but.grid(row = 2, column = 18)
def cont_select():
# Sorry about use of global! (it's useful for lazy/stupid people like me.)
global IP, IP_BOILER, IP_ROOM, DEST_PORT, DEST_PORT_BOILER, DEST_PORT_ROOM, IP_13amp
controller = cont_select_but.config('text')[-1]
if controller == "Boiler":
controller = "F/Room"
cont_select_but.config(text = controller)
DEST_PORT = DEST_PORT_ROOM
IP = IP_ROOM
get_data_remote()
elif controller == "F/Room":
controller = "13 Amp"
cont_select_but.config(text = controller)
DEST_PORT = DEST_PORT_ROOM
IP = IP_13amp
get_data_remote()
elif controller == "13 Amp":
controller = "Boiler"
cont_select_but.config(text = controller)
DEST_PORT = DEST_PORT_BOILER
IP = IP_BOILER
get_data_remote()
cont_select_but.config(command = cont_select)
#-------------------------------------------------------------------------------------------
ext_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Ext >")
ext_lab.grid(row = 14, column = 2, sticky = E)
ext_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
ext_but.grid(row = 14, column = 3, sticky = W)
flo_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Flo >")
flo_lab.grid(row = 14, column = 4, sticky = E)
flo_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
flo_but.grid(row = 14, column = 5, sticky = W)
ret_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Ret >")
ret_lab.grid(row = 14, column = 6, sticky = E)
ret_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
ret_but.grid(row = 14, column = 7, sticky = W)
#----------------------------------------------------------------------------------------
hall_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Hall >")
hall_lab.grid(row = 15, column = 2, sticky = E)
hall_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
hall_but.grid(row = 15, column = 3, sticky = W)
frm_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Frm >")
frm_lab.grid(row = 15, column = 4, sticky = E)
frm_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
frm_but.grid(row = 15, column = 5, sticky = W)
kit_lab = Label(app, font = ("Arial Bold", 16), bg = "gray", fg = "black", text = "Kit >")
kit_lab.grid(row = 15, column = 6, sticky = E)
kit_but = Button(app, font = ("Arial Bold", 16), bg = "gray", fg = "red", text = "xxx")
kit_but.grid(row = 15, column = 7, sticky = W)
#-----------------------------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 16)
#-----------------------------------------------------------------------------------
modeA_lab = Label(app, text = "Hi >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
modeA_lab.grid(row = 17, column = 2,  sticky = E)
modeA_but = Button(app, text = " A ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
modeA_but.grid(row = 17, column = 3,  sticky = W)
def modeA():
global Amode, Bmode, Cmode
but_col = modeA_but.config('bg')[-1]
if but_col == BUTTON_2:
but_col = "yellow"            
modeB_but.config(bg = BUTTON_2)
modeC_but.config(bg = BUTTON_2)
Amode = 1
Bmode = 0
Cmode = 0
else:
but_col = BUTTON_2
Amode = 0
modeA_but.config(bg = but_col)
modeA_but.config(command = modeA)
#---------------------------------------------------------------------------------
modeB_lab = Label(app, text = "Lo >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
modeB_lab.grid(row = 17, column = 4, sticky = E)
modeB_but = Button(app, text = " B ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
modeB_but.grid(row = 17, column = 5,  sticky = W)
def modeB():
global Amode, Bmode, Cmode
but_col = modeB_but.config('bg')[-1]
if but_col == BUTTON_2:
but_col = "yellow"
modeA_but.config(bg = BUTTON_2)
modeC_but.config(bg = BUTTON_2)
Amode = 0
Bmode = 1
Cmode = 0        
else:
but_col = BUTTON_2
Bmode = 0
modeB_but.config(bg = but_col)
modeB_but.config(command = modeB)
#---------------------------------------------------------------------------
modeC_lab = Label(app, text = "Rst >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
modeC_lab.grid(row = 17, column = 6,  sticky = E)
modeC_but = Button(app, text = " C ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
modeC_but.grid(row = 17, column = 7,  sticky = W)
def modeC():
global Amode, Bmode, Cmode
but_col = modeC_but.config('bg')[-1]
if but_col == BUTTON_2:
but_col = "yellow"
modeA_but.config(bg = BUTTON_2)
modeB_but.config(bg = BUTTON_2)
Amode = 0
Bmode = 0
Cmode = 1
else:
but_col = BUTTON_2
Cmode = 0
modeC_but.config(bg = but_col)
modeC_but.config(command = modeC)
#-------------------------------------------------------------
status_lab = Label(app, text = "Prog >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
status_lab.grid(row = 17, column = 9,  sticky = E)
status_but = Button(app, text = " X ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
status_but.grid(row = 17, column = 10,  sticky = W)
status_but2 = Button(app, text = " X ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
status_but2.grid(row = 17, column = 11,  sticky = E)
#-----------------------------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 18)
#------------------------------------------------------------------------------
lbl_modostat = Label(app, text = "Modulation Stat", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_modostat.grid(row = 19, column = 2, columnspan = 3, sticky = W)
#-----------------------------------------------------------------------
#option menu to ser modostat value
modo = StringVar(app)
modo.set(start_temp) # initial value
modostat_opt_men = OptionMenu(app,modo, "8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25")
modostat_opt_men.config(font = ("Arial", 14), fg = "black", bg = BUTTON_1, width = 2)
modostat_opt_men.grid(row = 20, column = 2, columnspan = 2, sticky = W)
#---------------------------------------------------------------------------------
use_modo_but = Button(app, text = "Use Modo", font = ("Arial", 16), fg = "black", bg = "pink")
use_modo_but.grid(row = 20, column = 3, columnspan = 3, sticky = W)
#-------------------------------------------------------------------------------
def use_modo() :
global set_modo_flag
but_col = use_modo_but.config('bg')[-1]
if but_col == BUTTON_1 :
use_modo_but.config(bg = "pink")
set_modo_flag = True
else:
use_modo_but.config(bg = BUTTON_1)
set_modo_flag = False
use_modo_but.config(command = use_modo)
#-------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 21)
#---------------------------------------------------------------------------
lbl_systime = Label(app, text = "Sys time >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_systime.grid(row = 22, column = 2,  sticky = W)
#------------------------------------------------------------------------
systime_but = Button(app, text = "xx:xx", font = ("Arial", 16), fg = "black", bg = BUTTON_2)
systime_but.grid(row = 22, column = 3,  sticky = E)
#-------------------------------------------------------------------
lbl_ardtime = Label(app, text = "Ard time >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_ardtime.grid(row = 22, column = 5,  sticky = W)
#------------------------------------------------------------------------------------------
ardtime_but = Button(app, text = "xx:xx", font = ("Arial", 16), fg = "black", bg = BUTTON_2)
ardtime_but.grid(row = 22, column = 6,  sticky = E)
#-------------------------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 23)
#---------------------------------------------------------------------------
lbl_lontime = Label(app, text = "Low on >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_lontime.grid(row = 24, column = 2,  sticky = W)
#---------------------------------------------------------------------------
lbl_low_ontime = Label(app, text = "xx:xx", font = ( "Arial ", 16), fg = "red", bg = BACKGROUND)
lbl_low_ontime.grid(row = 24, column = 3,  sticky = W)
#---------------------------------------------------------------------------
#-------------------------------------------------------------------------
lbl_lofftime = Label(app, text = "Low off >", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
lbl_lofftime.grid(row = 25, column = 2,  sticky = W)
#---------------------------------------------------------------------
lbl_low_offtime = Label(app, text = "xx:xx", font = ( "Arial ", 16), fg = "red", bg = BACKGROUND)
lbl_low_offtime.grid(row = 25, column = 3,  sticky = W)
#---------------------------------------------------------------------------
lo_on_update_but = Button(app, text = "U", font = ( "Arial ", 16), fg = "black", bg = BUTTON_2)
lo_on_update_but.grid(row = 24, column = 4,  sticky = W)
def update_lon() :
lbl_low_ontime.config(text = var6.get() + ":" + var7.get())
lo_on_update_but.config(command = update_lon)
#------------------------------------------------------------------------
lo_off_update_but = Button(app, text = "U", font = ( "Arial ", 16), fg = "black", bg = BUTTON_2)
lo_off_update_but.grid(row = 25, column = 4,  sticky = W)
def update_loff() :
lbl_low_offtime.config(text = var6.get() + ":" + var7.get())
lo_off_update_but.config(command = update_loff)
#---------------------------------------------------------------
load_mod_times_but = Button(app, text = "Load new times", font = ( "Arial ", 16), fg = "black", bg = BUTTON_1)
load_mod_times_but.grid(row = 24, column = 6,  sticky = W, columnspan = 3)
def upload_new_times() :
off_tim = lbl_low_offtime.cget("text")
off_hrs, off_mins = off_tim.split(":")
off_tim_num = str(int(off_hrs) * 60 + int(off_mins))
if len(off_tim_num) == 1 :
off_tim_num = "000" + off_tim_num
if len(off_tim_num) == 2 :
off_tim_num = "00" + off_tim_num
if len(off_tim_num) == 3 :
off_tim_num = "0" + off_tim_num
on_tim = lbl_low_ontime.cget("text")
on_hrs, on_mins = on_tim.split(":")
on_tim_num = str(int(on_hrs) * 60 + int(on_mins))
if len(on_tim_num) == 1 :
on_tim_num = "000" + on_tim_num
if len(on_tim_num) == 2 :
on_tim_num = "00" + on_tim_num
if len(on_tim_num) == 3 :
on_tim_num = "0" + on_tim_num
time_num = off_tim_num + on_tim_num
feedbackbut.config(text = time_num)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(bytes(time_num, "utf-8") , (IP_ARD, DEST_PORT_ARD))
except socket.error:
feedbackbut.config(text = "timed out!")
load_mod_times_but.config(command = upload_new_times)
#------------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 26)
#---------------------------------------------------------------------------
feedbacklab = Label(app, text = "F'back>", font = ( "Arial ", 16), fg = "black", bg = BACKGROUND)
feedbacklab.grid(row = 27, column = 2,  sticky = W)
#--------------------------------------------------------------------------
feedbackbut = Button(app, text = " XXXXX ", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
feedbackbut.grid(row = 27, column = 3,  sticky = E)
#-------------------------------------------------------------------------
clearbut = Button(app, text = "clear", font = ( "Arial ", 16), fg = "red", bg = BUTTON_2)
clearbut.grid(row = 27, column = 4,  sticky = W)
def clear() :
feedbackbut.config(text = " XXXXX ")
clearbut.config(command = clear)
#------------------------------------------------------------------------------
#blank row
blank_row = Label(app)
blank_row.grid(row = 28)
#---------------------------------------------------------------------------
# used for testing
testbut = Button(app, text = "test", font = ( "Arial ", 16), fg = "red", bg = "white")
testbut.grid(row = 29, column = 2,  sticky = W)
def get_test_vals() :
tim_test = str(int(var6.get()) * 60 + int(var7.get()))
if len(tim_test) == 1 :
tim_test = "000" + tim_test
if len(tim_test) == 2 :
tim_test = "00" + tim_test
if len(tim_test) == 3 :
tim_test = "0" + tim_test   
testbut.config(text = tim_test)
testbut.config(command = get_test_vals)
#-----------------------------------------------------------------------------
# used for testing
def sndData() :
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(bytes("10800570", "utf-8") , (IP_ARD, DEST_PORT_ARD))
except socket.error:
feedbackbut.config(text = "timed out!")
#--------------------------------------------------------
#used for testing
def send_data_bctrl() :
pass
#----------------------------------------------------
#update first immediately after prog is run
get_data_remote()
# calls a function after given time
def after(self, ms, func = None, *args):
"""call function after a given time"""
# updates screen every 10 seconds
def task():
get_data_remote()
clear_feedback()
root.after(10000, task)
# calls the screen update every 10 seconds
root.after(10000, task)
#---------------------------------------------------------------------------------------
# kick off the window's event-loop
root.mainloop()
Under Construction