Browse Source

support for lcd

Thomas Buck 8 months ago
parent
commit
920b42fab7
7 changed files with 469 additions and 21 deletions
  1. 6
    0
      python-test/copy.sh
  2. 44
    12
      python-test/flow.py
  3. 278
    0
      python-test/lcd.py
  4. 2
    2
      python-test/poll.py
  5. 11
    7
      python-test/scan.py
  6. 91
    0
      python-test/state_scan.py
  7. 37
    0
      python-test/states.py

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

@@ -5,6 +5,9 @@ cat << EOF | rshell
5 5
 cp flow.py /pyboard
6 6
 cp poll.py /pyboard
7 7
 cp scan.py /pyboard
8
+cp lcd.py /pyboard
9
+cp states.py /pyboard
10
+cp state_scan.py /pyboard
8 11
 cp $1 /pyboard/main.py
9 12
 EOF
10 13
 else
@@ -12,5 +15,8 @@ cat << EOF | rshell
12 15
 cp flow.py /pyboard
13 16
 cp poll.py /pyboard
14 17
 cp scan.py /pyboard
18
+cp lcd.py /pyboard
19
+cp states.py /pyboard
20
+cp state_scan.py /pyboard
15 21
 EOF
16 22
 fi

+ 44
- 12
python-test/flow.py View File

@@ -12,14 +12,22 @@ from poll import (
12 12
     get_state, set_state
13 13
 )
14 14
 
15
+terminal_width = 100 #os.get_terminal_size().columns - 15
16
+
15 17
 def print_bar(value, start, end, unit):
16
-    print("{}{} -> {}{} -> {}{}".format(start, unit, value, unit, end, unit))
18
+    width = terminal_width
19
+    s = "\r"
20
+    s += "#" * int((value - start) / (end - start) * width)
21
+    s += "-" * (width - int((value - start) / (end - start) * width))
22
+    s += " {}{}".format(value, unit)
23
+    print(s, end="")
17 24
 
18 25
 def sleep(t):
19 26
     print_bar(0, 0, t, "s")
20 27
     for i in range(0, t):
21 28
         time.sleep(1.0)
22 29
         print_bar(i + 1, 0, t, "s")
30
+    print()
23 31
 
24 32
 async def wait_for_temp(client, temp):
25 33
     print("Setting temperature {}".format(temp))
@@ -52,16 +60,16 @@ async def flow(client):
52 60
     print("Turning on heater")
53 61
     await set_state(client, (True, False))
54 62
 
55
-    await flow_step(client, 190.0, 20.0, 5.0 - 4.9)
56
-    await flow_step(client, 205.0, 10.0, 20.0 - 7)
57
-    await flow_step(client, 220.0, 10.0, 20.0 - 7)
63
+    await flow_step(client, 190.0, 15.0, 5.0 - 4)
64
+    await flow_step(client, 205.0, 10.0, 20.0 - 4)
65
+    await flow_step(client, 220.0, 10.0, 20.0 - 4)
58 66
 
59
-    #print("Notification by pumping three times...")
60
-    #for i in range(0, 3):
61
-    #    time.sleep(1.0 / 3)
62
-    #    await set_state(client, (True, True)) # turn on pump
63
-    #    time.sleep(1.0 / 3)
64
-    #    await set_state(client, (True, False)) # turn off pump
67
+    print("Notification by pumping three times...")
68
+    for i in range(0, 3):
69
+        #time.sleep(1.0 / 3)
70
+        await set_state(client, (True, True)) # turn on pump
71
+        #time.sleep(1.0 / 3)
72
+        await set_state(client, (True, False)) # turn off pump
65 73
 
66 74
     print("Turning heater off")
67 75
     await set_state(client, (False, False)) # turn off heater and pump
@@ -69,7 +77,7 @@ async def flow(client):
69 77
     print("Setting temperature back to 190")
70 78
     await set_target_temp(client, 190.0)
71 79
 
72
-if True:#__name__ == "__main__":
80
+if __name__ == "__main__":
73 81
     async def main(address):
74 82
         client = await ble_conn(address)
75 83
 
@@ -84,4 +92,28 @@ if True:#__name__ == "__main__":
84 92
             await set_state(client, (False, False)) # turn off heater and pump
85 93
             raise
86 94
 
87
-    asyncio.run(main(None))
95
+    import machine
96
+    led_onboard = machine.Pin("LED", machine.Pin.OUT)
97
+
98
+    for i in range(0, 3):
99
+        led_onboard.on()
100
+        time.sleep(0.2)
101
+        led_onboard.off()
102
+        time.sleep(0.2)
103
+
104
+    print("ready")
105
+    while True:
106
+        if rp2.bootsel_button() == 1:
107
+            led_onboard.on()
108
+            print("run")
109
+
110
+            try:
111
+                asyncio.run(main(None))
112
+                print("done")
113
+            except Exception as e:
114
+                print(e)
115
+
116
+            led_onboard.off()
117
+            machine.reset()
118
+
119
+        time.sleep(0.2)

+ 278
- 0
python-test/lcd.py View File

@@ -0,0 +1,278 @@
1
+# https://www.waveshare.com/wiki/Pico-LCD-1.3
2
+
3
+from machine import Pin, SPI, PWM
4
+import framebuf
5
+import time
6
+import os
7
+
8
+class KeyCheck:
9
+    def __init__(self, new, old):
10
+        self.new = new
11
+        self.old = old
12
+
13
+    def once(self, k):
14
+        return self.new[k] and not self.old[k]
15
+
16
+class LCD(framebuf.FrameBuffer):
17
+    def __init__(self):
18
+        self.width = 240
19
+        self.height = 240
20
+
21
+        self.cs = Pin(9, Pin.OUT)
22
+        self.rst = Pin(12, Pin.OUT)
23
+
24
+        self.cs(1)
25
+
26
+        #self.spi = SPI(1)
27
+        #self.spi = SPI(1,   1_000_000)
28
+        self.spi = SPI(1, 100_000_000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11), miso=None)
29
+
30
+        self.dc = Pin(8, Pin.OUT)
31
+        self.dc(1)
32
+
33
+        self.buffer = bytearray(self.height * self.width * 2)
34
+
35
+        super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
36
+        self.init_display()
37
+
38
+        self.red   = 0x07E0
39
+        self.green = 0x001f
40
+        self.blue  = 0xf800
41
+        self.white = 0xffff
42
+        self.black = 0x0000
43
+
44
+        self.fill(self.black)
45
+        self.show()
46
+
47
+        self.pwm = PWM(Pin(13))
48
+        self.pwm.freq(1000)
49
+        self.brightness(0.0)
50
+
51
+        self.keyA = Pin(15,Pin.IN,Pin.PULL_UP)
52
+        self.keyB = Pin(17,Pin.IN,Pin.PULL_UP)
53
+        self.keyX = Pin(19 ,Pin.IN,Pin.PULL_UP)
54
+        self.keyY= Pin(21 ,Pin.IN,Pin.PULL_UP)
55
+
56
+        self.up = Pin(2,Pin.IN,Pin.PULL_UP)
57
+        self.down = Pin(18,Pin.IN,Pin.PULL_UP)
58
+        self.left = Pin(16,Pin.IN,Pin.PULL_UP)
59
+        self.right = Pin(20,Pin.IN,Pin.PULL_UP)
60
+        self.ctrl = Pin(3,Pin.IN,Pin.PULL_UP)
61
+
62
+        self.keys_old = {
63
+            "a": False,
64
+            "b": False,
65
+            "x": False,
66
+            "y": False,
67
+            "up": False,
68
+            "down": False,
69
+            "left": False,
70
+            "right": False,
71
+            "enter": False,
72
+        }
73
+
74
+    def buttons(self):
75
+        keys = {
76
+            "a": self.keyA.value() == 0,
77
+            "b": self.keyB.value() == 0,
78
+            "x": self.keyX.value() == 0,
79
+            "y": self.keyY.value() == 0,
80
+            "up": self.up.value() == 0,
81
+            "down": self.down.value() == 0,
82
+            "left": self.left.value() == 0,
83
+            "right": self.right.value() == 0,
84
+            "enter": self.ctrl.value() == 0,
85
+        }
86
+        kc = KeyCheck(keys, self.keys_old)
87
+        self.keys_old = keys.copy()
88
+        return kc
89
+
90
+    def brightness(self, v):
91
+        self.pwm.duty_u16(int(v * 65535))
92
+
93
+    def write_cmd(self, cmd):
94
+        self.cs(1)
95
+        self.dc(0)
96
+        self.cs(0)
97
+        self.spi.write(bytearray([cmd]))
98
+        self.cs(1)
99
+
100
+    def write_data(self, buf):
101
+        self.cs(1)
102
+        self.dc(1)
103
+        self.cs(0)
104
+        self.spi.write(bytearray([buf]))
105
+        self.cs(1)
106
+
107
+    def init_display(self):
108
+        self.rst(1)
109
+        self.rst(0)
110
+        self.rst(1)
111
+
112
+        self.write_cmd(0x36)
113
+        self.write_data(0x70)
114
+
115
+        self.write_cmd(0x3A) 
116
+        self.write_data(0x05)
117
+
118
+        self.write_cmd(0xB2)
119
+        self.write_data(0x0C)
120
+        self.write_data(0x0C)
121
+        self.write_data(0x00)
122
+        self.write_data(0x33)
123
+        self.write_data(0x33)
124
+
125
+        self.write_cmd(0xB7)
126
+        self.write_data(0x35) 
127
+
128
+        self.write_cmd(0xBB)
129
+        self.write_data(0x19)
130
+
131
+        self.write_cmd(0xC0)
132
+        self.write_data(0x2C)
133
+
134
+        self.write_cmd(0xC2)
135
+        self.write_data(0x01)
136
+
137
+        self.write_cmd(0xC3)
138
+        self.write_data(0x12)   
139
+
140
+        self.write_cmd(0xC4)
141
+        self.write_data(0x20)
142
+
143
+        self.write_cmd(0xC6)
144
+        self.write_data(0x0F) 
145
+
146
+        self.write_cmd(0xD0)
147
+        self.write_data(0xA4)
148
+        self.write_data(0xA1)
149
+
150
+        self.write_cmd(0xE0)
151
+        self.write_data(0xD0)
152
+        self.write_data(0x04)
153
+        self.write_data(0x0D)
154
+        self.write_data(0x11)
155
+        self.write_data(0x13)
156
+        self.write_data(0x2B)
157
+        self.write_data(0x3F)
158
+        self.write_data(0x54)
159
+        self.write_data(0x4C)
160
+        self.write_data(0x18)
161
+        self.write_data(0x0D)
162
+        self.write_data(0x0B)
163
+        self.write_data(0x1F)
164
+        self.write_data(0x23)
165
+
166
+        self.write_cmd(0xE1)
167
+        self.write_data(0xD0)
168
+        self.write_data(0x04)
169
+        self.write_data(0x0C)
170
+        self.write_data(0x11)
171
+        self.write_data(0x13)
172
+        self.write_data(0x2C)
173
+        self.write_data(0x3F)
174
+        self.write_data(0x44)
175
+        self.write_data(0x51)
176
+        self.write_data(0x2F)
177
+        self.write_data(0x1F)
178
+        self.write_data(0x1F)
179
+        self.write_data(0x20)
180
+        self.write_data(0x23)
181
+        
182
+        self.write_cmd(0x21)
183
+
184
+        self.write_cmd(0x11)
185
+
186
+        self.write_cmd(0x29)
187
+
188
+    def show(self):
189
+        self.write_cmd(0x2A)
190
+        self.write_data(0x00)
191
+        self.write_data(0x00)
192
+        self.write_data(0x00)
193
+        self.write_data(0xef)
194
+        
195
+        self.write_cmd(0x2B)
196
+        self.write_data(0x00)
197
+        self.write_data(0x00)
198
+        self.write_data(0x00)
199
+        self.write_data(0xEF)
200
+
201
+        self.write_cmd(0x2C)
202
+
203
+        self.cs(1)
204
+        self.dc(1)
205
+        self.cs(0)
206
+        self.spi.write(self.buffer)
207
+        self.cs(1)
208
+
209
+if __name__  == '__main__':
210
+    lcd = LCD()
211
+    lcd.brightness(1.0)
212
+
213
+    try:
214
+        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)
270
+
271
+            lcd.show()
272
+            time.sleep(0.1)
273
+    except KeyboardInterrupt:
274
+        pass
275
+
276
+    lcd.fill(lcd.black)
277
+    lcd.show()
278
+    lcd.brightness(0.0)

+ 2
- 2
python-test/poll.py View File

@@ -13,9 +13,9 @@ async def ble_conn(address):
13 13
     dev = await ble_scan(address)
14 14
 
15 15
     if dev:
16
-        address = dev.addr_hex()
16
+        address = dev.device.addr_hex()
17 17
         print("Connecting to '{}'...".format(address))
18
-        connection = await dev.connect()
18
+        connection = await dev.device.connect()
19 19
         return connection
20 20
 
21 21
     return None

+ 11
- 7
python-test/scan.py View File

@@ -5,18 +5,22 @@ import aioble
5 5
 import bluetooth
6 6
 import sys
7 7
 
8
-async def ble_scan(addr = None, timeout = 0.1):
9
-    print("Scanning for '{}' for {}s...".format(addr, timeout))
8
+async def ble_scan(addr = None, name = "S&B VOLCANO H", timeout = 0.5):
9
+    #print("Scanning for '{}' for {}s...".format(addr, timeout))
10 10
     scanner = aioble.scan(int(timeout * 1000.0), interval_us=30000, window_us=30000, active=True)
11 11
     async with scanner as s:
12
+        results = []
12 13
         async for d in s:
13
-            print("Scan: '{}' [{}]".format(d.name(), d.device.addr_hex()))
14
+            #print("Scan: '{}' [{}]".format(d.name(), d.device.addr_hex()))
14 15
             if addr != None:
15 16
                 if addr == d.device.addr_hex():
16
-                    return d.device
17
+                    return d
18
+            elif name != None:
19
+                if d.name() == name:
20
+                    return d
17 21
             else:
18
-                if d.name() == "S&B VOLCANO H":
19
-                    return d.device
22
+                results.append(d)
23
+        return results
20 24
 
21 25
     print("No device found")
22 26
     return None
@@ -24,4 +28,4 @@ async def ble_scan(addr = None, timeout = 0.1):
24 28
 if __name__ == "__main__":
25 29
     dev = asyncio.run(ble_scan())
26 30
     if dev != None:
27
-        print("{}".format(dev.addr_hex()))
31
+        print("{}".format(dev.device.addr_hex()))

+ 91
- 0
python-test/state_scan.py View File

@@ -0,0 +1,91 @@
1
+#!/usr/bin/env python
2
+
3
+import uasyncio as asyncio
4
+from scan import ble_scan
5
+from flow import flow
6
+
7
+class StateScan:
8
+    def __init__(self, lcd):
9
+        self.lcd = lcd
10
+
11
+        self.lock = asyncio.Lock()
12
+
13
+    def enter(self):
14
+        self.scanner = asyncio.create_task(self.scan())
15
+        self.results = []
16
+        self.current = None
17
+
18
+    def exit(self):
19
+        self.scanner.cancel()
20
+
21
+        if self.lock.locked():
22
+            self.lock.release()
23
+
24
+    async def scan(self):
25
+        while True:
26
+            new = await ble_scan(None, None, 0.25)
27
+
28
+            async with self.lock:
29
+                for n in new:
30
+                    found = False
31
+                    for r in self.results:
32
+                        if r.device.addr_hex() == n.device.addr_hex():
33
+                            found = True
34
+                            r = n
35
+                            break
36
+                    if not found:
37
+                        self.results.append(n)
38
+
39
+    def draw_list(self):
40
+        for i, d in enumerate(self.results):
41
+            s1 = "{}".format(d.name())
42
+            s2 = "{} - {}".format(i + 1, d.device.addr_hex())
43
+
44
+            off = i * 25 + 30
45
+            if off >= self.lcd.height:
46
+                break
47
+
48
+            c1 = self.lcd.white
49
+            if s1 == "S&B VOLCANO H":
50
+                c1 = self.lcd.green
51
+                if self.current == None:
52
+                    self.current = i
53
+            elif self.current == i:
54
+                c1 = self.lcd.red
55
+            c2 = self.lcd.white
56
+            if self.current == i:
57
+                c2 = self.lcd.red
58
+
59
+            self.lcd.hline(0, off, self.lcd.width, self.lcd.blue)
60
+            self.lcd.text(s1, 0, off + 2, c1)
61
+            self.lcd.text(s2, 0, off + 12, c2)
62
+
63
+    async def draw(self):
64
+        self.lcd.fill(self.lcd.black)
65
+
66
+        self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
67
+        self.lcd.text("Scanning for Bluetooth devices", 0, 10, self.lcd.red)
68
+
69
+        keys = self.lcd.buttons()
70
+
71
+        async with self.lock:
72
+            if keys.once("enter"):
73
+                if self.current < len(self.results):
74
+                    #return 1 # connect
75
+                    client = await self.results[self.current].device.connect()
76
+                    await flow(client)
77
+            elif keys.once("up"):
78
+                if self.current == None:
79
+                    self.current = len(self.results) - 1
80
+                elif self.current > 0:
81
+                    self.current -= 1
82
+            elif keys.once("down"):
83
+                if self.current == None:
84
+                    self.current = 0
85
+                elif self.current < (len(self.results) - 1):
86
+                    self.current += 1
87
+
88
+            self.draw_list()
89
+
90
+        self.lcd.show()
91
+        return -1 # stay in this state

+ 37
- 0
python-test/states.py View File

@@ -0,0 +1,37 @@
1
+#!/usr/bin/env python
2
+
3
+import uasyncio as asyncio
4
+from lcd import LCD
5
+from state_scan import StateScan
6
+
7
+class States:
8
+    def __init__(self):
9
+        self.states = []
10
+        self.current = None
11
+
12
+    def add(self, s):
13
+        self.states.append(s)
14
+
15
+    def run(self):
16
+        if self.current == None:
17
+            self.current = 0
18
+            self.states[self.current].enter()
19
+
20
+        next = asyncio.run(self.states[self.current].draw())
21
+        if next >= 0:
22
+            self.states[self.current].exit()
23
+            self.current = next
24
+            self.states[self.current].enter()
25
+
26
+if True:#__name__ == "__main__":
27
+    lcd = LCD()
28
+    lcd.brightness(1.0)
29
+
30
+    states = States()
31
+
32
+    # 0 - Scan
33
+    scan = StateScan(lcd)
34
+    states.add(scan)
35
+
36
+    while True:
37
+        states.run()

Loading…
Cancel
Save