-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.py
More file actions
169 lines (139 loc) · 5.51 KB
/
Copy pathcode.py
File metadata and controls
169 lines (139 loc) · 5.51 KB
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
"""AutoFan controller"""
import time
import board
import pulseio
import busio
import digitalio
#import gc # enable for memory stat access
from adafruit_ht16k33.matrix import Matrix8x8
from adafruit_mcp230xx.mcp23008 import MCP23008
from adafruit_debouncer import Debouncer
from analogio import AnalogIn
# print("AutoFan - PWM fan controller")
cycle_time = 245 # microseconds
# transition_rate = 20 # ~microseconds change per second (measured from real fan controller)
frequency = int(1000000 / cycle_time) # PWM frequency
speed_pwm_values = [65535, 43600, 38786, 33436, 28086, 22201, 16049, 9362, 0]
current_speed = 0
current_PWM = speed_pwm_values[current_speed]
change_rate = 100 # rate of PWM change when changing fan speeds
blink_rate = 3
# setup PWM pin
PWMpin = pulseio.PWMOut(board.D4, frequency=frequency, duty_cycle=0)
# setup current sensing pin
sense_pin = AnalogIn(board.A0)
sense_smoothed = 0; # smoothed sense value. Default 0V
# setup sense threshold trim pot pin
threshold_pin = AnalogIn(board.A3)
threshold_setting = 3.3; # default high so fan doesn't turn on during init
# setup I2C bus
i2c = busio.I2C(board.SCL, board.SDA, frequency=400000)
# setup Led Matrix display
matrix = Matrix8x8(i2c)
matrix.brightness = 0.1 # WARNING: keep low until power is moved to non-trinket source
matrix[current_speed, 7] = 1
# setup up/down buttons via MCP23008 IO expander
mcp = MCP23008(i2c)
pin0 = mcp.get_pin(0)
pin0.direction = digitalio.Direction.INPUT
pin0.pull = digitalio.Pull.UP
pin1 = mcp.get_pin(1)
pin1.direction = digitalio.Direction.INPUT
pin1.pull = digitalio.Pull.UP
pin2 = mcp.get_pin(2)
pin2.direction = digitalio.Direction.INPUT
pin2.pull = digitalio.Pull.UP
debounce_interval = 0.05
down_btn = Debouncer(pin0, interval=debounce_interval) # ==False when pressed
up_btn = Debouncer(pin1, interval=debounce_interval) # ==False when pressed
mode_switch = Debouncer(pin2, interval=debounce_interval) # True == Manual, False == Auto
manual_mode = mode_switch.value
#print("Init: manual_mode: {0}".format(manual_mode))
#if manual_mode == True:
# matrix.blink_rate = blink_rate
target_PWM = speed_pwm_values[current_speed]
PWMpin.duty_cycle = current_PWM
def set_speed(new_speed):
global current_speed
global current_PWM
global target_PWM
if new_speed != current_speed:
print("new speed: {0}".format(new_speed))
update_display(new_speed)
if current_speed == 0:
# do immediate transition from speed 0 to 1 (then gradual to final speed)
current_PWM = speed_pwm_values[1] + 1 # +1 to get transition logic to set actual pin PWM
# if setting speed 0, then only go to 1 and let "PWM cut-off" logic do the final step
if new_speed == 0:
target_PWM = speed_pwm_values[1]
else:
target_PWM = speed_pwm_values[new_speed]
current_speed = new_speed
# print("current speed: {0} current PWM: {1} target PWM: {2}".format(new_speed, current_PWM, target_PWM))
def update_display(level):
global matrix
matrix.fill(0)
if level < 1:
return
for x in range(0, level):
for y in range(0, x+1):
matrix[x, 7-y] = 1
update_display(current_speed)
def is_load_on():
global threshold_setting
global sense_smoothed
sense_volts = (sense_pin.value * 3.3) / 65536
threshold_volts = (threshold_pin.value * 3.3) / 65536
# apply simple smoothing to incomming signals
sense_smoothed = sense_smoothed * 0.95 + sense_volts * 0.05
threshold_setting = threshold_setting * 0.95 + threshold_volts * 0.05
# print("sense voltage: {0:2.3f}V threshold voltage: {1:2.3f}V threshold setting: {2:2.3f}V".format(sense_volts, threshold_volts, threshold_setting))
# time.sleep(0.01)
if sense_volts > threshold_setting:
return True
return False
while True:
mode_switch.update()
# check mode switch and set correct mode
if mode_switch.fell: # switch to auto mode
manual_mode = False
# matrix.blink_rate = 0
print("Auto mode selected")
elif mode_switch.rose:
manual_mode = True
# matrix.blink_rate = blink_rate
print("Manual mode selected")
# execute mode specific logic
if manual_mode == True: # manual mode
down_btn.update()
up_btn.update()
if down_btn.fell and current_speed > 0:
# print("free mem: {0}".format(gc.mem_free()))
set_speed(current_speed - 1)
elif up_btn.fell and current_speed < 8:
# print("free mem: {0}".format(gc.mem_free()))
set_speed(current_speed + 1)
else: # auto mode
load_on = is_load_on()
if load_on == True and current_speed != 8:
set_speed(8)
elif load_on == False and current_speed != 0:
set_speed(0)
# smoothly transition current_PWM to target_PWM setting
if (current_PWM < target_PWM):
current_PWM += change_rate
if current_PWM > target_PWM:
current_PWM = target_PWM
PWMpin.duty_cycle = current_PWM
elif current_PWM > target_PWM:
current_PWM -= change_rate
if current_PWM < target_PWM:
current_PWM = target_PWM
PWMpin.duty_cycle = current_PWM
elif current_speed == 0 and current_PWM == speed_pwm_values[1] :
# PWM cut-off logic
# turn off immediately when we reached the target speed of 1. (no gradual transition from 1 to 0)
current_PWM = speed_pwm_values[0]
target_PWM = speed_pwm_values[0]
PWMpin.duty_cycle = current_PWM
# time.sleep(0.01)