Browse Source

simplepyble, untested

Thomas Buck 1 year ago
parent
commit
78c9daca6b
4 changed files with 142 additions and 130 deletions
  1. 1
    0
      python-test/.gitignore
  2. 38
    40
      python-test/flow.py
  3. 68
    78
      python-test/poll.py
  4. 35
    12
      python-test/scan.py

+ 1
- 0
python-test/.gitignore View File

1
+venv

+ 38
- 40
python-test/flow.py View File

1
 #!/usr/bin/env python
1
 #!/usr/bin/env python
2
 
2
 
3
 import sys
3
 import sys
4
-import asyncio
4
+import time
5
+import os
6
+
5
 from poll import (
7
 from poll import (
6
     ble_conn,
8
     ble_conn,
7
     get_current_temp,
9
     get_current_temp,
10
     get_state, set_state
12
     get_state, set_state
11
 )
13
 )
12
 
14
 
13
-terminal_width = 80 + 20 # TODO detect?
15
+terminal_width = os.get_terminal_size().columns - 15
14
 
16
 
15
 def print_bar(value, start, end, unit):
17
 def print_bar(value, start, end, unit):
16
     width = terminal_width
18
     width = terminal_width
20
     s += " {}{}".format(value, unit)
22
     s += " {}{}".format(value, unit)
21
     print(s, end="", flush=True)
23
     print(s, end="", flush=True)
22
 
24
 
23
-async def sleep(t):
25
+def sleep(t):
24
     w = terminal_width
26
     w = terminal_width
25
     if t < w:
27
     if t < w:
26
         w = int(t)
28
         w = int(t)
27
     print_bar(0, 0, w, "s")
29
     print_bar(0, 0, w, "s")
28
     for i in range(0, w):
30
     for i in range(0, w):
29
-        await asyncio.sleep(t / w)
31
+        time.sleep(t / w)
30
         print_bar(i + 1, 0, w, "s")
32
         print_bar(i + 1, 0, w, "s")
31
     print()
33
     print()
32
 
34
 
33
-async def wait_for_temp(client, temp):
35
+def wait_for_temp(client, temp):
34
     print("Setting temperature {}".format(temp))
36
     print("Setting temperature {}".format(temp))
35
-    await set_target_temp(client, temp)
37
+    set_target_temp(client, temp)
36
 
38
 
37
     print("Waiting for temperature to rise...")
39
     print("Waiting for temperature to rise...")
38
-    start = await get_current_temp(client)
40
+    start = get_current_temp(client)
39
     curr = start
41
     curr = start
40
     print_bar(curr, start, temp, " degC")
42
     print_bar(curr, start, temp, " degC")
41
     while curr < temp:
43
     while curr < temp:
42
-        await asyncio.sleep(1.0)
43
-        curr = await get_current_temp(client)
44
+        time.sleep(1.0)
45
+        curr = get_current_temp(client)
44
         print_bar(curr, start, temp, " degC")
46
         print_bar(curr, start, temp, " degC")
45
     print()
47
     print()
46
 
48
 
47
     print("Reached temperature {}".format(temp))
49
     print("Reached temperature {}".format(temp))
48
 
50
 
49
-async def flow_step(client, temp, t_wait, t_pump):
50
-    await wait_for_temp(client, temp)
51
+def flow_step(client, temp, t_wait, t_pump):
52
+    wait_for_temp(client, temp)
51
 
53
 
52
     print("Waiting {}s for heat to settle...".format(t_wait))
54
     print("Waiting {}s for heat to settle...".format(t_wait))
53
-    await sleep(t_wait)
55
+    sleep(t_wait)
54
 
56
 
55
     print("Pumping for {}s".format(t_pump))
57
     print("Pumping for {}s".format(t_pump))
56
-    await set_state(client, (True, True)) # turn on pump
57
-    await sleep(t_pump)
58
-    await set_state(client, (True, False)) # turn off pump
58
+    set_state(client, (True, True)) # turn on pump
59
+    sleep(t_pump)
60
+    set_state(client, (True, False)) # turn off pump
59
 
61
 
60
-async def flow(client):
62
+def flow(client):
61
     print("Turning on heater")
63
     print("Turning on heater")
62
-    await set_state(client, (True, False))
64
+    set_state(client, (True, False))
63
 
65
 
64
-    await flow_step(client, 190.0, 20.0, 5.0)
65
-    await flow_step(client, 205.0, 10.0, 20.0)
66
-    await flow_step(client, 220.0, 10.0, 20.0)
66
+    flow_step(client, 190.0, 20.0, 5.0)
67
+    flow_step(client, 205.0, 10.0, 20.0)
68
+    flow_step(client, 220.0, 10.0, 20.0)
67
 
69
 
68
     print("Notification by pumping three times...")
70
     print("Notification by pumping three times...")
69
     for i in range(0, 3):
71
     for i in range(0, 3):
70
-        await asyncio.sleep(1.0)
71
-        await set_state(client, (True, True)) # turn on pump
72
-        await asyncio.sleep(1.0)
73
-        await set_state(client, (True, False)) # turn off pump
72
+        time.sleep(1.0)
73
+        set_state(client, (True, True)) # turn on pump
74
+        time.sleep(1.0)
75
+        set_state(client, (True, False)) # turn off pump
74
 
76
 
75
     print("Turning heater off")
77
     print("Turning heater off")
76
-    await set_state(client, (False, False)) # turn off heater and pump
78
+    set_state(client, (False, False)) # turn off heater and pump
77
 
79
 
78
-async def main(address):
79
-    device = await ble_conn(address)
80
+if __name__ == "__main__":
81
+    def main(address):
82
+        device = ble_conn(address)
80
 
83
 
81
-    print("Connecting...")
82
-    async with device as client:
83
         try:
84
         try:
84
-            if await get_unit_is_fahrenheit(client):
85
-                print("Imperial American scum is currently not supported :P")
86
-                sys.exit(42)
85
+            if get_unit_is_fahrenheit(client):
86
+                raise RuntimeError("Imperial American scum is currently not supported :P")
87
 
87
 
88
             print("Starting Workflow")
88
             print("Starting Workflow")
89
-            await flow(client)
89
+            flow(client)
90
         except:
90
         except:
91
             print("\nTurning heater off")
91
             print("\nTurning heater off")
92
-            await set_state(client, (False, False)) # turn off heater and pump
92
+            set_state(client, (False, False)) # turn off heater and pump
93
             raise
93
             raise
94
 
94
 
95
         print("Disconnecting...")
95
         print("Disconnecting...")
96
 
96
 
97
-if __name__ == "__main__":
98
-    if len(sys.argv) <= 1:
99
-        print("Please pass MAC address of device")
100
-        sys.exit(1)
101
-
102
-    asyncio.run(main(sys.argv[1]))
97
+    arg = None
98
+    if len(sys.argv) > 1:
99
+        arg = sys.argv[1]
100
+    main(arg)

+ 68
- 78
python-test/poll.py View File

1
 #!/usr/bin/env python
1
 #!/usr/bin/env python
2
 
2
 
3
-import sys
4
-import asyncio
5
-from bleak import BleakClient, BleakScanner
6
-from bleak.exc import BleakDBusError
7
-
8
-async def ble_conn(address):
9
-    attempts = 10
10
-    print("Opening device..", end = "", flush=True)
11
-    while attempts > 0:
12
-        try:
13
-            if (attempts % 10) == 0:
14
-                print(".", end = "", flush=True)
15
-
16
-            device = await BleakScanner.find_device_by_address(address)
17
-            client = BleakClient(device)
18
-            print("", flush=True)
19
-            return client
20
-        except BleakDBusError as e:
21
-            attempts -= 1
22
-            if attempts == 0:
23
-                print("", flush=True)
24
-                print(e)
25
-            else:
26
-                await asyncio.sleep(0.1)
27
-
28
-    print("Could not connect to device")
29
-    return None
30
-
31
-async def get_current_temp(client):
32
-    val = await client.read_gatt_char("10110001-5354-4f52-5a26-4249434b454c")
3
+import simplepyble
4
+from scan import ble_scan
5
+import time
6
+
7
+serviceUuidVolcano3 = "10100000-5354-4f52-5a26-4249434b454c"
8
+serviceUuidVolcano4 = "10110000-5354-4f52-5a26-4249434b454c"
9
+
10
+def ble_conn(address):
11
+    dev = ble_scan(address)
12
+
13
+    if dev != None:
14
+        print("Connecting to {}...".format(address))
15
+        dev.connect()
16
+
17
+    return dev
18
+
19
+def get_current_temp(device):
20
+    val = device.read(serviceUuidVolcano4, "10110001-5354-4f52-5a26-4249434b454c")
33
     num = int.from_bytes(val, byteorder="little")
21
     num = int.from_bytes(val, byteorder="little")
34
     return num / 10.0
22
     return num / 10.0
35
 
23
 
36
-async def get_target_temp(client):
37
-    val = await client.read_gatt_char("10110003-5354-4f52-5a26-4249434b454c")
24
+def get_target_temp(device):
25
+    val = device.read(serviceUuidVolcano4, "10110003-5354-4f52-5a26-4249434b454c")
38
     num = int.from_bytes(val, byteorder="little")
26
     num = int.from_bytes(val, byteorder="little")
39
     return num / 10.0
27
     return num / 10.0
40
 
28
 
41
-async def set_target_temp(client, temp):
29
+def set_target_temp(device, temp):
42
     val = int(temp * 10.0)
30
     val = int(temp * 10.0)
43
     d = val.to_bytes(4, byteorder="little")
31
     d = val.to_bytes(4, byteorder="little")
44
-    await client.write_gatt_char("10110003-5354-4f52-5a26-4249434b454c", d)
32
+    device.write_request(serviceUuidVolcano4, "10110003-5354-4f52-5a26-4249434b454c", d)
45
 
33
 
46
-async def get_unit_is_fahrenheit(client):
47
-    val = await client.read_gatt_char("1010000d-5354-4f52-5a26-4249434b454c")
34
+def get_unit_is_fahrenheit(device):
35
+    val = device.read(serviceUuidVolcano3, "1010000d-5354-4f52-5a26-4249434b454c")
48
     num = int.from_bytes(val, byteorder="little")
36
     num = int.from_bytes(val, byteorder="little")
49
     return (num & 0x200) != 0
37
     return (num & 0x200) != 0
50
 
38
 
51
-async def get_state(client):
52
-    val = await client.read_gatt_char("1010000c-5354-4f52-5a26-4249434b454c")
39
+def get_state(device):
40
+    val = device.read(serviceUuidVolcano3, "1010000c-5354-4f52-5a26-4249434b454c")
53
     num = int.from_bytes(val, byteorder="little")
41
     num = int.from_bytes(val, byteorder="little")
54
     heater = (num & 0x0020) != 0
42
     heater = (num & 0x0020) != 0
55
     pump = (num & 0x2000) != 0
43
     pump = (num & 0x2000) != 0
56
     return (heater, pump)
44
     return (heater, pump)
57
 
45
 
58
-async def set_state(client, state):
46
+def set_state(device, state):
59
     heater, pump = state
47
     heater, pump = state
60
     if heater:
48
     if heater:
61
-        await client.write_gatt_char("1011000f-5354-4f52-5a26-4249434b454c", 0)
49
+        device.write_request(serviceUuidVolcano4, "1011000f-5354-4f52-5a26-4249434b454c", 0)
62
     else:
50
     else:
63
-        await client.write_gatt_char("10110010-5354-4f52-5a26-4249434b454c", 0)
51
+        device.write_request(serviceUuidVolcano4, "10110010-5354-4f52-5a26-4249434b454c", 0)
64
     if pump:
52
     if pump:
65
-        await client.write_gatt_char("10110013-5354-4f52-5a26-4249434b454c", 0)
66
-    else:
67
-        await client.write_gatt_char("10110014-5354-4f52-5a26-4249434b454c", 0)
68
-
69
-async def test_poll(client):
70
-    temp = await get_current_temp(client)
71
-    print("Current Temperature: {}".format(temp))
72
-
73
-    target = await get_target_temp(client)
74
-    print("Target Temperature: {}".format(target))
75
-
76
-    fahrenheit = await get_unit_is_fahrenheit(client)
77
-    if fahrenheit:
78
-        print("Unit is Fahrenheit")
53
+        device.write_request(serviceUuidVolcano4, "10110013-5354-4f52-5a26-4249434b454c", 0)
79
     else:
54
     else:
80
-        print("Unit is Celsius")
55
+        device.write_request(serviceUuidVolcano4, "10110014-5354-4f52-5a26-4249434b454c", 0)
81
 
56
 
82
-    heater, pump = await get_state(client)
83
-    if heater:
84
-        print("Heater is On")
85
-    else:
86
-        print("Heater is Off")
87
-    if pump:
88
-        print("Pump is On")
89
-    else:
90
-        print("Pump is Off")
91
-
92
-async def test(address):
93
-    device = await ble_conn(address)
57
+if __name__ == "__main__":
58
+    def test_poll(device):
59
+        temp = get_current_temp(device)
60
+        print("Current Temperature: {}".format(temp))
61
+
62
+        target = get_target_temp(device)
63
+        print("Target Temperature: {}".format(target))
64
+
65
+        fahrenheit = get_unit_is_fahrenheit(device)
66
+        if fahrenheit:
67
+            print("Unit is Fahrenheit")
68
+        else:
69
+            print("Unit is Celsius")
70
+
71
+        heater, pump = get_state(device)
72
+        if heater:
73
+            print("Heater is On")
74
+        else:
75
+            print("Heater is Off")
76
+        if pump:
77
+            print("Pump is On")
78
+        else:
79
+            print("Pump is Off")
80
+
81
+    def test(address):
82
+        device = ble_conn(address)
83
+        if device == None:
84
+            return
94
 
85
 
95
-    print("Connecting...")
96
-    async with device as client:
97
         print("Writing...")
86
         print("Writing...")
98
-        await set_target_temp(client, 190.0)
87
+        set_target_temp(device, 190.0)
99
 
88
 
100
         print("Reading...")
89
         print("Reading...")
101
         for i in range(0, 5):
90
         for i in range(0, 5):
102
-            await test_poll(client)
91
+            test_poll(device)
103
             print()
92
             print()
104
-            await asyncio.sleep(2.0)
93
+            time.sleep(2.0)
105
 
94
 
106
-if __name__ == "__main__":
107
-    if len(sys.argv) <= 1:
108
-        print("Please pass MAC address of device")
109
-        sys.exit(1)
95
+    import sys
96
+
97
+    arg = None
98
+    if len(sys.argv) > 1:
99
+        arg = sys.argv[1]
110
 
100
 
111
-    asyncio.run(test(sys.argv[1]))
101
+    test(arg)

+ 35
- 12
python-test/scan.py View File

1
-#!/usr/bin/env python
1
+import simplepyble
2
 
2
 
3
-import asyncio
4
-from bleak import BleakScanner
3
+def ble_scan(addr):
4
+    adapters = simplepyble.Adapter.get_adapters()
5
 
5
 
6
-async def scan():
7
-    print("scanning for 5 seconds, please wait...")
8
-    devices = await BleakScanner.discover(return_adv=True)
9
-    for d, a in devices.values():
10
-        print()
11
-        print(d)
12
-        print("-" * len(str(d)))
13
-        print(a)
6
+    if len(adapters) == 0:
7
+        print("No adapters found")
8
+        return None
9
+
10
+    # TODO allow selection of bluetooth adapter
11
+    adapter = adapters[0]
12
+    print("Selected adapter: {} [{}]".format(adapter.identifier(), adapter.address()))
13
+
14
+    # TODO support longer scans?
15
+    print("Scanning for '{}' for 1s...".format(addr))
16
+    adapter.scan_for(1000)
17
+
18
+    peripherals = adapter.scan_get_results()
19
+    for peripheral in peripherals:
20
+        if addr != None:
21
+            if addr == peripheral.address():
22
+                return peripheral
23
+        else:
24
+            if peripheral.identifier() == "S&B VOLCANO H":
25
+                return peripheral
26
+
27
+    print("No device found")
28
+    return None
14
 
29
 
15
 if __name__ == "__main__":
30
 if __name__ == "__main__":
16
-    asyncio.run(scan())
31
+    import sys
32
+
33
+    arg = None
34
+    if len(sys.argv) > 1:
35
+        arg = sys.argv[1]
36
+
37
+    dev = ble_scan(arg)
38
+    if dev != None:
39
+        print("{} {}".format(dev.identifier(), dev.address()))

Loading…
Cancel
Save