Thomas Buck 8 months ago
parent
commit
7e855a7ddb

+ 2
- 0
python-test/copy.sh View File

@@ -15,6 +15,7 @@ cp state_heat.py /pyboard
15 15
 cp state_wait_temp.py /pyboard
16 16
 cp state_wait_time.py /pyboard
17 17
 cp state_pump.py /pyboard
18
+cp state_notify.py /pyboard
18 19
 cp $1 /pyboard/main.py
19 20
 EOF
20 21
 else
@@ -32,6 +33,7 @@ cp state_heat.py /pyboard
32 33
 cp state_wait_temp.py /pyboard
33 34
 cp state_wait_time.py /pyboard
34 35
 cp state_pump.py /pyboard
36
+cp state_notify.py /pyboard
35 37
 rm /pyboard/main.py
36 38
 EOF
37 39
 fi

+ 115
- 55
python-test/lcd.py View File

@@ -1,9 +1,13 @@
1 1
 # https://www.waveshare.com/wiki/Pico-LCD-1.3
2
+# https://thepihut.com/blogs/raspberry-pi-tutorials/coding-graphics-with-micropython-on-raspberry-pi-pico-displays
3
+# https://api.arcade.academy/en/latest/_modules/arcade/draw_commands.html#draw_arc_filled
2 4
 
3 5
 from machine import Pin, SPI, PWM
6
+from array import array
4 7
 import framebuf
5 8
 import time
6 9
 import os
10
+import math
7 11
 
8 12
 class KeyCheck:
9 13
     def __init__(self, new, old):
@@ -206,67 +210,123 @@ class LCD(framebuf.FrameBuffer):
206 210
         self.spi.write(self.buffer)
207 211
         self.cs(1)
208 212
 
213
+    def circle(self, x, y, r, c):
214
+        self.hline(x-r,y,r*2,c)
215
+        for i in range(1,r):
216
+            a = int(math.sqrt(r*r-i*i)) # Pythagoras!
217
+            self.hline(x-a,y+i,a*2,c) # Lower half
218
+            self.hline(x-a,y-i,a*2,c) # Upper half
219
+
220
+    def ring(self, x, y, r, c):
221
+        self.pixel(x-r,y,c)
222
+        self.pixel(x+r,y,c)
223
+        self.pixel(x,y-r,c)
224
+        self.pixel(x,y+r,c)
225
+        for i in range(1, r):
226
+            a = int(math.sqrt(r*r-i*i))
227
+            self.pixel(x-a,y-i,c)
228
+            self.pixel(x+a,y-i,c)
229
+            self.pixel(x-a,y+i,c)
230
+            self.pixel(x+a,y+i,c)
231
+            self.pixel(x-i,y-a,c)
232
+            self.pixel(x+i,y-a,c)
233
+            self.pixel(x-i,y+a,c)
234
+            self.pixel(x+i,y+a,c)
235
+
236
+    def arc(self, x_off, y_off, w, h, c,
237
+                   start_angle, end_angle,
238
+                   filled = True,
239
+                   num_segments = 128):
240
+        point_list = [0, 0]
241
+
242
+        start_segment = int(start_angle / 360 * num_segments)
243
+        end_segment = int(end_angle / 360 * num_segments)
244
+
245
+        for segment in range(start_segment, end_segment + 1):
246
+            theta = 2.0 * 3.1415926 * segment / num_segments
247
+            x = w * math.cos(theta) / 2
248
+            y = h * math.sin(theta) / 2
249
+            point_list.append(int(x))
250
+            point_list.append(int(y))
251
+
252
+        self.poly(int(x_off), int(y_off), array('h', point_list), c, True)
253
+
254
+    def pie(self, x0, y0, w, c_border, c_circle, v):
255
+        if v > 0.0:
256
+            lcd.arc(int(x0), int(y0), int(w), int(w), c_circle, -90, int(v * 360) - 90)
257
+        lcd.ring(int(x0), int(y0), int(w / 2), c_border)
258
+
209 259
 if __name__  == '__main__':
260
+    start = time.time()
261
+    def gfx_test(lcd):
262
+        v = (time.time() - start)
263
+        lcd.fill(lcd.black)
264
+        lcd.pie(lcd.width / 2, lcd.height / 2, lcd.width, lcd.red, lcd.green, (v % 11) / 10)
265
+
266
+    def key_test(lcd):
267
+        lcd.fill(lcd.white)
268
+
269
+        if lcd.keyA.value() == 0:
270
+            lcd.fill_rect(208,15,30,30,lcd.red)
271
+        else:
272
+            lcd.fill_rect(208,15,30,30,lcd.white)
273
+            lcd.rect(208,15,30,30,lcd.red)
274
+
275
+        if lcd.keyB.value() == 0:
276
+            lcd.fill_rect(208,75,30,30,lcd.red)
277
+        else:
278
+            lcd.fill_rect(208,75,30,30,lcd.white)
279
+            lcd.rect(208,75,30,30,lcd.red)
280
+
281
+        if lcd.keyX.value() == 0:
282
+            lcd.fill_rect(208,135,30,30,lcd.red)
283
+        else:
284
+            lcd.fill_rect(208,135,30,30,lcd.white)
285
+            lcd.rect(208,135,30,30,lcd.red)
286
+
287
+        if lcd.keyY.value() == 0:
288
+            lcd.fill_rect(208,195,30,30,lcd.red)
289
+        else:
290
+            lcd.fill_rect(208,195,30,30,lcd.white)
291
+            lcd.rect(208,195,30,30,lcd.red)
292
+
293
+        if lcd.up.value() == 0:
294
+            lcd.fill_rect(60,60,30,30,lcd.red)
295
+        else:
296
+            lcd.fill_rect(60,60,30,30,lcd.white)
297
+            lcd.rect(60,60,30,30,lcd.red)
298
+
299
+        if lcd.down.value() == 0:
300
+            lcd.fill_rect(60,150,30,30,lcd.red)
301
+        else:
302
+            lcd.fill_rect(60,150,30,30,lcd.white)
303
+            lcd.rect(60,150,30,30,lcd.red)
304
+
305
+        if lcd.left.value() == 0:
306
+            lcd.fill_rect(15,105,30,30,lcd.red)
307
+        else:
308
+            lcd.fill_rect(15,105,30,30,lcd.white)
309
+            lcd.rect(15,105,30,30,lcd.red)
310
+
311
+        if lcd.right.value() == 0:
312
+            lcd.fill_rect(105,105,30,30,lcd.red)
313
+        else:
314
+            lcd.fill_rect(105,105,30,30,lcd.white)
315
+            lcd.rect(105,105,30,30,lcd.red)
316
+
317
+        if lcd.ctrl.value() == 0:
318
+            lcd.fill_rect(60,105,30,30,lcd.red)
319
+        else:
320
+            lcd.fill_rect(60,105,30,30,lcd.white)
321
+            lcd.rect(60,105,30,30,lcd.red)
322
+
210 323
     lcd = LCD()
211 324
     lcd.brightness(1.0)
212 325
 
213 326
     try:
214 327
         while True:
215
-            lcd.fill(lcd.white)
216
-
217
-            if lcd.keyA.value() == 0:
218
-                lcd.fill_rect(208,15,30,30,lcd.red)
219
-            else:
220
-                lcd.fill_rect(208,15,30,30,lcd.white)
221
-                lcd.rect(208,15,30,30,lcd.red)
222
-
223
-            if lcd.keyB.value() == 0:
224
-                lcd.fill_rect(208,75,30,30,lcd.red)
225
-            else:
226
-                lcd.fill_rect(208,75,30,30,lcd.white)
227
-                lcd.rect(208,75,30,30,lcd.red)
228
-
229
-            if lcd.keyX.value() == 0:
230
-                lcd.fill_rect(208,135,30,30,lcd.red)
231
-            else:
232
-                lcd.fill_rect(208,135,30,30,lcd.white)
233
-                lcd.rect(208,135,30,30,lcd.red)
234
-
235
-            if lcd.keyY.value() == 0:
236
-                lcd.fill_rect(208,195,30,30,lcd.red)
237
-            else:
238
-                lcd.fill_rect(208,195,30,30,lcd.white)
239
-                lcd.rect(208,195,30,30,lcd.red)
240
-
241
-            if lcd.up.value() == 0:
242
-                lcd.fill_rect(60,60,30,30,lcd.red)
243
-            else:
244
-                lcd.fill_rect(60,60,30,30,lcd.white)
245
-                lcd.rect(60,60,30,30,lcd.red)
246
-
247
-            if lcd.down.value() == 0:
248
-                lcd.fill_rect(60,150,30,30,lcd.red)
249
-            else:
250
-                lcd.fill_rect(60,150,30,30,lcd.white)
251
-                lcd.rect(60,150,30,30,lcd.red)
252
-
253
-            if lcd.left.value() == 0:
254
-                lcd.fill_rect(15,105,30,30,lcd.red)
255
-            else:
256
-                lcd.fill_rect(15,105,30,30,lcd.white)
257
-                lcd.rect(15,105,30,30,lcd.red)
258
-
259
-            if lcd.right.value() == 0:
260
-                lcd.fill_rect(105,105,30,30,lcd.red)
261
-            else:
262
-                lcd.fill_rect(105,105,30,30,lcd.white)
263
-                lcd.rect(105,105,30,30,lcd.red)
264
-
265
-            if lcd.ctrl.value() == 0:
266
-                lcd.fill_rect(60,105,30,30,lcd.red)
267
-            else:
268
-                lcd.fill_rect(60,105,30,30,lcd.white)
269
-                lcd.rect(60,105,30,30,lcd.red)
328
+            #key_test(lcd)
329
+            gfx_test(lcd)
270 330
 
271 331
             lcd.show()
272 332
             time.sleep(0.1)

+ 3
- 7
python-test/state_connect.py View File

@@ -29,7 +29,7 @@ class StateConnect:
29 29
             self.done = False
30 30
 
31 31
         if self.state:
32
-            client = await d.device.connect()
32
+            client = await d[0].device.connect()
33 33
             async with self.lock:
34 34
                 self.step = True
35 35
             await cache_services_characteristics(client)
@@ -39,12 +39,9 @@ class StateConnect:
39 39
 
40 40
         async with self.lock:
41 41
             self.done = True
42
-            self.client = client
42
+            self.client = (client, d[1])
43 43
 
44 44
     async def draw(self):
45
-        self.lcd.fill(self.lcd.black)
46
-
47
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
48 45
         self.lcd.text("Connecting to Bluetooth device", 0, 10, self.lcd.red)
49 46
 
50 47
         keys = self.lcd.buttons()
@@ -59,7 +56,7 @@ class StateConnect:
59 56
         async with self.lock:
60 57
             if self.done:
61 58
                 if self.state:
62
-                    return 2 # selection
59
+                    return 3 # heater on
63 60
                 else:
64 61
                     return 0 # scan
65 62
             else:
@@ -71,5 +68,4 @@ class StateConnect:
71 68
                     else:
72 69
                         self.lcd.text("Fetching parameters...", 0, int(self.lcd.height / 2) - 5, self.lcd.white)
73 70
 
74
-        self.lcd.show()
75 71
         return -1 # stay in this state

+ 19
- 7
python-test/state_heat.py View File

@@ -1,7 +1,7 @@
1 1
 #!/usr/bin/env python
2 2
 
3 3
 import uasyncio as asyncio
4
-from poll import set_state
4
+from poll import set_state, set_target_temp
5 5
 
6 6
 class StateHeat:
7 7
     def __init__(self, lcd, state):
@@ -14,6 +14,7 @@ class StateHeat:
14 14
         self.value = val
15 15
         self.heater = asyncio.create_task(self.heat())
16 16
         self.done = False
17
+        self.step = False
17 18
 
18 19
     def exit(self):
19 20
         self.heater.cancel()
@@ -24,19 +25,26 @@ class StateHeat:
24 25
         return (self.value[0], self.value[1], 0)
25 26
 
26 27
     async def heat(self):
27
-        print("Setting heater: {}".format(self.state))
28 28
         pump = None
29 29
         if self.state == False:
30 30
             pump = False
31
+
32
+        print("Setting heater: {}".format(self.state))
31 33
         await set_state(self.value[0], (self.state, pump))
32 34
 
35
+        if self.state == False:
36
+            async with self.lock:
37
+                self.step = True
38
+
39
+            temp = self.value[1]["reset_temperature"]
40
+            if temp != None:
41
+                print("Reset temperature to default value")
42
+                await set_target_temp(self.value[0], temp)
43
+
33 44
         async with self.lock:
34 45
             self.done = True
35 46
 
36 47
     async def draw(self):
37
-        self.lcd.fill(self.lcd.black)
38
-
39
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
40 48
         self.lcd.text("Running Workflow - Heat {}".format(self.state), 0, 10, self.lcd.red)
41 49
 
42 50
         keys = self.lcd.buttons()
@@ -47,6 +55,8 @@ class StateHeat:
47 55
                 async with self.lock:
48 56
                     if self.done:
49 57
                         return 4 # heat off
58
+                    else:
59
+                        return 5 # disconnect
50 60
             else:
51 61
                 return 5 # disconnect
52 62
 
@@ -58,9 +68,11 @@ class StateHeat:
58 68
                     return 6 # wait for temperature
59 69
             else:
60 70
                 if self.state == False:
61
-                    self.lcd.text("Turning heater off...", 0, int(self.lcd.height / 2) - 5, self.lcd.white)
71
+                    if self.state == False:
72
+                        self.lcd.text("Turning heater off...", 0, int(self.lcd.height / 2) - 5, self.lcd.white)
73
+                    else:
74
+                        self.lcd.text("Resetting temperature...", 0, int(self.lcd.height / 2) - 5, self.lcd.white)
62 75
                 else:
63 76
                     self.lcd.text("Turning heater on...", 0, int(self.lcd.height / 2) - 5, self.lcd.white)
64 77
 
65
-        self.lcd.show()
66 78
         return -1 # stay in this state

+ 56
- 0
python-test/state_notify.py View File

@@ -0,0 +1,56 @@
1
+#!/usr/bin/env python
2
+
3
+import time
4
+import uasyncio as asyncio
5
+from poll import set_state
6
+from state_wait_temp import draw_graph
7
+
8
+class StateNotify:
9
+    def __init__(self, lcd):
10
+        self.lcd = lcd
11
+
12
+        self.lock = asyncio.Lock()
13
+
14
+    def enter(self, val = None):
15
+        self.value = val
16
+        self.notifier = asyncio.create_task(self.notify())
17
+        self.done = False
18
+
19
+    def exit(self):
20
+        self.notifier.cancel()
21
+
22
+        if self.lock.locked():
23
+            self.lock.release()
24
+
25
+        return (self.value[0], self.value[1], self.value[2])
26
+
27
+    async def notify(self):
28
+        device, workflow, index = self.value
29
+        count, duration = workflow["notify"]
30
+
31
+        for i in range(0, count):
32
+            print("Turning on pump")
33
+            await set_state(device, (None, True))
34
+            await asyncio.sleep_ms(int(duration * 1000))
35
+
36
+            print("Turning off pump")
37
+            await set_state(device, (None, False))
38
+            await asyncio.sleep_ms(int(duration * 1000))
39
+
40
+        async with self.lock:
41
+            self.done = True
42
+
43
+    async def draw(self):
44
+        self.lcd.text("Running Workflow - Notify", 0, 10, self.lcd.red)
45
+
46
+        keys = self.lcd.buttons()
47
+
48
+        if keys.once("y"):
49
+            print("user abort")
50
+            return 4 # heat off
51
+
52
+        async with self.lock:
53
+            if self.done:
54
+                return 4 # heater off
55
+
56
+        return -1 # stay in this state

+ 4
- 6
python-test/state_pump.py View File

@@ -44,10 +44,7 @@ class StatePump:
44 44
             self.done = True
45 45
 
46 46
     async def draw(self):
47
-        self.lcd.fill(self.lcd.black)
48
-
49 47
         device, workflow, index = self.value
50
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
51 48
         self.lcd.text("Running Workflow - Pump {}".format(workflow["steps"][index][2]), 0, 10, self.lcd.red)
52 49
 
53 50
         keys = self.lcd.buttons()
@@ -68,10 +65,11 @@ class StatePump:
68 65
 
69 66
             if self.done:
70 67
                 if self.value[2] >= (len(workflow["steps"]) - 1):
71
-                    # TODO notify
72
-                    return 4 # heater off
68
+                    if workflow["notify"] != None:
69
+                        return 9 # notify
70
+                    else:
71
+                        return 4 # heater off
73 72
                 else:
74 73
                     return 6 # wait for temperature
75 74
 
76
-        self.lcd.show()
77 75
         return -1 # stay in this state

+ 1
- 5
python-test/state_scan.py View File

@@ -62,9 +62,6 @@ class StateScan:
62 62
             self.lcd.text(s2, 0, off + 12, c2)
63 63
 
64 64
     async def draw(self):
65
-        self.lcd.fill(self.lcd.black)
66
-
67
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
68 65
         self.lcd.text("Scanning for Bluetooth devices", 0, 10, self.lcd.red)
69 66
 
70 67
         keys = self.lcd.buttons()
@@ -72,7 +69,7 @@ class StateScan:
72 69
         async with self.lock:
73 70
             if keys.once("enter"):
74 71
                 if self.current < len(self.results):
75
-                    return 1 # connect
72
+                    return 2 # select
76 73
             elif keys.once("up"):
77 74
                 if self.current == None:
78 75
                     self.current = len(self.results) - 1
@@ -86,5 +83,4 @@ class StateScan:
86 83
 
87 84
             self.draw_list()
88 85
 
89
-        self.lcd.show()
90 86
         return -1 # stay in this state

+ 1
- 5
python-test/state_select.py View File

@@ -32,9 +32,6 @@ class StateSelect:
32 32
             self.lcd.text(s2, 0, off + 12, c)
33 33
 
34 34
     async def draw(self):
35
-        self.lcd.fill(self.lcd.black)
36
-
37
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
38 35
         self.lcd.text("Please select your Workflow", 0, 10, self.lcd.red)
39 36
 
40 37
         keys = self.lcd.buttons()
@@ -49,9 +46,8 @@ class StateSelect:
49 46
             if self.current < (len(workflows) - 1):
50 47
                 self.current += 1
51 48
         elif keys.once("enter"):
52
-            return 3 # heater on
49
+            return 1 # connect
53 50
 
54 51
         self.draw_list()
55 52
 
56
-        self.lcd.show()
57 53
         return -1 # stay in this state

+ 8
- 8
python-test/state_wait_temp.py View File

@@ -10,10 +10,14 @@ def draw_graph(lcd, min, val, max):
10 10
 
11 11
     w = lcd.width - 10
12 12
     ratio = (val - min) / (max - min)
13
-    wfull = int(w * ratio)
14
-    wempty = w - wfull
15
-    lcd.rect(4, int(lcd.height / 2) - 5, wfull + 1, 50, lcd.green, True)
16
-    lcd.rect(4 + wfull, int(lcd.height / 2) - 5, wempty + 2, 50, lcd.green, False)
13
+
14
+    #wfull = int(w * ratio)
15
+    #wempty = w - wfull
16
+    #lcd.rect(4, int(lcd.height / 2) - 5, wfull + 1, 50, lcd.green, True)
17
+    #lcd.rect(4 + wfull, int(lcd.height / 2) - 5, wempty + 2, 50, lcd.green, False)
18
+
19
+    lcd.pie(lcd.width / 2, lcd.height / 2, w, lcd.red, lcd.green, ratio)
20
+
17 21
     lcd.text("{}".format(val), int(lcd.width / 2), 125, lcd.white)
18 22
 
19 23
 class StateWaitTemp:
@@ -60,10 +64,7 @@ class StateWaitTemp:
60 64
                 self.temp = temp
61 65
 
62 66
     async def draw(self):
63
-        self.lcd.fill(self.lcd.black)
64
-
65 67
         device, workflow, index = self.value
66
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
67 68
         self.lcd.text("Running Workflow - Heat {}".format(workflow["steps"][index][0]), 0, 10, self.lcd.red)
68 69
 
69 70
         keys = self.lcd.buttons()
@@ -82,5 +83,4 @@ class StateWaitTemp:
82 83
                 print("switch, {} >= {}".format(self.temp, self.max))
83 84
                 return 7 # wait for time
84 85
 
85
-        self.lcd.show()
86 86
         return -1 # stay in this state

+ 0
- 4
python-test/state_wait_time.py View File

@@ -18,10 +18,7 @@ class StateWaitTime:
18 18
         return (self.value[0], self.value[1], self.value[2])
19 19
 
20 20
     async def draw(self):
21
-        self.lcd.fill(self.lcd.black)
22
-
23 21
         device, workflow, index = self.value
24
-        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
25 22
         self.lcd.text("Running Workflow - Wait {}".format(workflow["steps"][index][1]), 0, 10, self.lcd.red)
26 23
 
27 24
         keys = self.lcd.buttons()
@@ -37,5 +34,4 @@ class StateWaitTime:
37 34
             print("switch, {} >= {}".format(now, self.end))
38 35
             return 8 # pump
39 36
 
40
-        self.lcd.show()
41 37
         return -1 # stay in this state

+ 19
- 3
python-test/states.py View File

@@ -9,21 +9,30 @@ from state_heat import StateHeat
9 9
 from state_wait_temp import StateWaitTemp
10 10
 from state_wait_time import StateWaitTime
11 11
 from state_pump import StatePump
12
+from state_notify import StateNotify
12 13
 
13 14
 class States:
14
-    def __init__(self):
15
+    def __init__(self, lcd):
16
+        self.lcd = lcd
15 17
         self.states = []
16 18
         self.current = None
17 19
 
18 20
     def add(self, s):
19 21
         self.states.append(s)
20 22
 
23
+    async def draw(self):
24
+        self.lcd.fill(self.lcd.black)
25
+        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
26
+        r = await self.states[self.current].draw()
27
+        self.lcd.show()
28
+        return r
29
+
21 30
     def run(self):
22 31
         if self.current == None:
23 32
             self.current = 0
24 33
             self.states[self.current].enter()
25 34
 
26
-        next = asyncio.run(self.states[self.current].draw())
35
+        next = asyncio.run(self.draw())
27 36
         if next >= 0:
28 37
             print("switch to {}".format(next))
29 38
             val = self.states[self.current].exit()
@@ -34,17 +43,20 @@ if True:#__name__ == "__main__":
34 43
     lcd = LCD()
35 44
     lcd.brightness(1.0)
36 45
 
37
-    states = States()
46
+    states = States(lcd)
38 47
 
39 48
     # 0 - Scan
49
+    # passes ScanResult to 2, select
40 50
     scan = StateScan(lcd)
41 51
     states.add(scan)
42 52
 
43 53
     # 1 - Connect
54
+    # passes device and selected workflow to 3, heater on
44 55
     conn = StateConnect(lcd, True)
45 56
     states.add(conn)
46 57
 
47 58
     # 2 - Select
59
+    # passes ScanResult and selected workflow to 1, connect
48 60
     select = StateSelect(lcd)
49 61
     states.add(select)
50 62
 
@@ -72,5 +84,9 @@ if True:#__name__ == "__main__":
72 84
     pump = StatePump(lcd)
73 85
     states.add(pump)
74 86
 
87
+    # 9 - Notify
88
+    notify = StateNotify(lcd)
89
+    states.add(notify)
90
+
75 91
     while True:
76 92
         states.run()

+ 4
- 0
python-test/workflows.py View File

@@ -9,6 +9,8 @@ workflows = [
9 9
             (205.0, 10.0, 20.0),
10 10
             (220.0, 10.0, 20.0),
11 11
         ],
12
+        "notify": (3, 1.0),
13
+        "reset_temperature": 190.0,
12 14
     },
13 15
     {
14 16
         "name": "Vorbi",
@@ -19,5 +21,7 @@ workflows = [
19 21
             (204.0, 3.0, 10.0),
20 22
             (217.0, 5.0, 10.0),
21 23
         ],
24
+        "notify": None,
25
+        "reset_temperature": None,
22 26
     },
23 27
 ]

Loading…
Cancel
Save