forked from brycesub/silvia-pi
-
Notifications
You must be signed in to change notification settings - Fork 2
/
silvia-pi.py
executable file
·177 lines (149 loc) · 4.42 KB
/
silvia-pi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/python3
import logging
from datetime import datetime as dt
logger = logging.getLogger('silvia')
logger.setLevel(logging.INFO)
fh = logging.FileHandler('/home/pi/silvia-pi/logs/%s.log' % dt.strftime(dt.now(), '%Y-%m-%d'))
fh.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
def he_control_loop(lock,state):
from heat import Heat
try:
heat_control = Heat(state)
heat_control.run()
except Exception as e:
logger.error(e)
finally:
logger.info("----------------Closing heat control----------------")
heat_control.cleanup()
def pid_loop(lock,state):
from sensor import Sensor
try:
pid = Sensor(state)
pid.run()
except Exception as e:
logger.error(e)
finally:
logger.info("--------------------Closing PID---------------------")
pid.cleanup()
def pygame_gui(lock, state):
from chart import Chart
try:
Chart.start_pygame()
c = Chart(0.5, 30, state)
c.run()
except Exception as e:
logger.error(e)
finally:
logger.info("--------------------Closing GUI---------------------")
Chart.stop_pygame()
def gpio_temp_control(lock, state):
from gpiozero import Button
from time import time
from config import config
import os
os.system('gpio -g mode 18 pwm | gpio pwmc 1000 | gpio -g pwm 18 800')
def increase():
logger.info("Increase button pressed")
state['settemp'] += 0.2
config.set_temp = state['settemp']
config.save()
def decrease():
logger.info("Decrease button pressed")
state['settemp'] -= 0.2
config.set_temp = state['settemp']
config.save()
def toggle():
logger.info("Exit button pressed")
state['on'] = not state['on']
if state['on']:
os.system('gpio -g pwm 18 800')
else:
os.system('gpio -g pwm 18 100')
def set_boost():
logger.info("Heating for 5 seconds")
state['boost'] = time() + 5
up = Button(17)
up.when_pressed = increase
down = Button(22)
down.when_pressed = decrease
kill = Button(27)
kill.when_pressed = toggle
boost = Button(23)
boost.when_pressed = set_boost
return up, down, kill, boost
def print_exception(*info):
import traceback
tb = ''.join(traceback.format_exception(*info))
logger.error("Uncaught error: ")
logger.error(tb)
if __name__ == '__main__':
from multiprocessing import Process, Manager, Lock
from time import sleep
from config import config as conf
import sys
from formatter import PartialFormatter
sys.excepthook = print_exception
lock = Lock()
manager = Manager()
pidstate = manager.dict()
pidstate['snooze'] = conf.snooze
pidstate['snoozeon'] = False
pidstate['i'] = 0
pidstate['settemp'] = conf.set_temp
pidstate['avgpid'] = 0.
pidstate['temp'] = 0.
pidstate['heating'] = False
pidstate['avgtemp'] = None
pidstate['exit'] = False
pidstate['pterm'] = None
pidstate['iterm'] = None
pidstate['dterm'] = None
pidstate['sterm'] = None
pidstate['pidval'] = None
pidstate['boost'] = 0
pidstate['on'] = True
pidstate['gui_on'] = False
logger.info('Main process started')
logger.info('Starting PID loop')
p = Process(target=pid_loop,args=(lock, pidstate))
p.daemon = True
p.start()
logger.info('Starting heat control')
h = Process(target=he_control_loop,args=(lock, pidstate))
h.daemon = True
h.start()
logger.info('Starting GUI')
gui = Process(target=pygame_gui, args=(lock, pidstate))
gui.daemon = True
gui.start()
while not pidstate['gui_on']:
sleep(1)
up, down, kill, boost = gpio_temp_control(lock, pidstate)
logger.info('Buttons assigned')
logger.info('Starting status loop')
fmt = PartialFormatter()
dir(fmt)
while p.is_alive and gui.is_alive and h.is_alive and not pidstate['exit']:
try:
print(fmt.format('P: {pterm:7.2f}\tI: {iterm:7.2f}\tD: {dterm:7.2f}\tS: {sterm:7.2f}\tOut: {pidval:7.2f} Avg PID: {avgpid:7.2f}\tTemp: {temp:7.2f}\tAvg Temp: {avgtemp:7.2f}', **pidstate))
sleep(1)
except KeyboardInterrupt:
logger.error('Keyboard interrupt, exiting')
break
except Exception as e:
logger.error('Error in status loop:')
logger.error(str(e))
break
logger.info('Killing PID process')
p.terminate()
logger.info('Killing heat control process')
h.terminate()
logger.info('Killing GUI process')
gui.terminate()
p.join()
h.join()
gui.join()
logging.info('All threads joined, exiting')