Skip to content

Commit 6d7805c

Browse files
committed
update docs
1 parent d60e9ff commit 6d7805c

7 files changed

Lines changed: 169 additions & 28 deletions

File tree

README.rst

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,12 @@ PythonHere
2727
- *Here* is a server part with the GUI interface. It could be Android, Raspberry Pi, some other remote device that being debugged.
2828
- And *%there* is a client - Jupyter magic command to run code interactively on remote device.
2929

30-
Project documentation: https://herethere.me
31-
32-
.. |jupyter| image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/left_jupyter.png
33-
:align: middle
34-
:height: 400
35-
.. |android| image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/right_android.png
36-
:align: middle
37-
:height: 400
30+
This app could serve as a Python Kivy playground, for dynamic code execution from the PC.
3831

39-
.. list-table::
40-
:widths: 50 50
41-
:header-rows: 1
32+
Project documentation: https://herethere.me
4233

43-
* - Jupyter on PC
44-
- Android app
45-
* - |jupyter|
46-
- |android|
34+
.. image:: https://raw.githubusercontent.com/b3b/pythonhere/master/docs/description.png
35+
:alt: Project description
4736

4837

4938
Install on Android
@@ -104,7 +93,7 @@ To build with `Buildozer <https://github.com/kivy/buildozer>`_, run in the sourc
10493
Related resources
10594
-----------------
10695

107-
* `Kivy Remote Shell <https://github.com/kivy/kivy-remote-shell>`_: Remote SSH+Python interactive shell application
96+
* `Kivy Remote Shell <https://github.com/kivy/kivy-remote-shell>`_ : Remote SSH+Python interactive shell application
10897
* `herethere <https://github.com/b3b/herethere>`_ : Library for interactive code execution, based on AsyncSSH
10998
* `AsyncSSH <https://github.com/ronf/asyncssh>`_ : Asynchronous SSH for Python
11099
* `Buildozer action <https://github.com/ArtemSBulgakov/buildozer-action>`_ : GitHub action that is used to build Android APK with Buildozer

buildozer.spec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ android.api = 29
5858
android.minapi = 22
5959
android.ndk = 20b
6060

61+
# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
62+
android.arch = armeabi-v7a
63+
6164
android.permissions =
6265
WAKE_LOCK,
6366
ACCESS_NETWORK_STATE,

docs/description.png

110 KB
Loading

docs/left_jupyter.png

-96.6 KB
Binary file not shown.

docs/right_android.png

-21.7 KB
Binary file not shown.

examples/android.md

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ Android platform features could be used with [PyJNIus](https://github.com/kivy/p
2222

2323
```python
2424
%%there
25+
from pathlib import Path
2526
from kivy.logger import Logger
2627
from android.permissions import Permission, check_permission, request_permission
2728
import plyer
2829
```
2930

31+
```python
32+
%there -b log
33+
```
34+
3035
## Show notification
3136

3237
```python
@@ -73,24 +78,24 @@ touch /sdcard/test_python_here
7378

7479
### Request runtime permission
7580

76-
```python
77-
%there -bl 1 log
78-
```
79-
8081
```python
8182
%%there
82-
8383
def permissions_callback(permissions, grant_results):
8484
if permissions and all(grant_results):
85-
Logger.info("Runtime permissions: granted")
85+
Logger.info("Runtime permissions: granted %s", permissions)
8686
else:
87-
Logger.error("Runtime permissions: not granted")
87+
Logger.error("Runtime permissions: not granted, %s", permissions)
8888

89-
permission = Permission.WRITE_EXTERNAL_STORAGE
90-
if check_permission(permission):
91-
print(f"{permission} is already granted")
92-
else:
93-
request_permission(permission, callback=permissions_callback)
89+
def ask_permission(permission):
90+
if check_permission(permission):
91+
print(f"{permission} is already granted")
92+
else:
93+
request_permission(permission, callback=permissions_callback)
94+
```
95+
96+
```python
97+
%%there
98+
ask_permission(Permission.WRITE_EXTERNAL_STORAGE)
9499
```
95100

96101
The system permission prompt should appear at this point.
@@ -112,3 +117,29 @@ touch /sdcard/test_python_here.txt
112117
cat /sdcard/test_python_here.txt
113118
rm /sdcard/test_python_here.txt
114119
```
120+
121+
## Take picture with a camera
122+
Camera could be displayed and captured with the Kivy [Camera](https://kivy.org/doc/stable/api-kivy.uix.camera.html) widget.
123+
124+
```python
125+
%%there
126+
ask_permission(Permission.CAMERA)
127+
```
128+
129+
```python
130+
%%there kv
131+
Camera:
132+
play: True
133+
```
134+
135+
```python
136+
%%there
137+
root.export_to_png(filename=str(Path("camera.png").resolve()))
138+
root.play = False
139+
```
140+
141+
```python
142+
%%there shell
143+
file camera.png
144+
rm camera.png
145+
```

examples/ble.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
jupyter:
3+
jupytext:
4+
text_representation:
5+
extension: .md
6+
format_name: markdown
7+
format_version: '1.2'
8+
jupytext_version: 1.7.1
9+
kernelspec:
10+
display_name: Python 3
11+
language: python
12+
name: python3
13+
---
14+
15+
# Android Bluetooth Low Energy functions
16+
BLE functions could be used with the [able](https://github.com/b3b/able) library.
17+
18+
```python
19+
%load_ext pythonhere
20+
%connect-there
21+
```
22+
23+
```python
24+
%%there
25+
from kivy.logger import Logger
26+
from able import BluetoothDispatcher, GATT_SUCCESS
27+
```
28+
29+
BLE dispatcher callbacks results should be printed in logs:
30+
31+
```python
32+
%there -b log
33+
```
34+
35+
## Setup BLE interface
36+
with logging callbacks
37+
38+
```python
39+
%%there
40+
class BLE(BluetoothDispatcher):
41+
42+
def on_connection_state_change(self, status, state):
43+
Logger.info("on_connection_state_change: status=%s, state=%s", status, state)
44+
if status == GATT_SUCCESS and state:
45+
Logger.info("Connection: succeed")
46+
47+
def on_services(self, status, services):
48+
Logger.info("on_services: status=%s", status)
49+
if status == GATT_SUCCESS:
50+
Logger.info("services discovered: %s", list(services.keys()))
51+
# save discovered services object
52+
self.services = services
53+
54+
def on_characteristic_read(self, characteristic, status):
55+
Logger.info("on_characteristic_read: status=%s, characteristic=%s", status,
56+
characteristic.getUuid().toString())
57+
if status == GATT_SUCCESS:
58+
Logger.info("Characteristic read: succeed")
59+
60+
61+
ble = BLE()
62+
print(ble)
63+
```
64+
65+
## Connect to remote device by a hardware address
66+
In this example device hardware address address is known.
67+
68+
```python
69+
%%there
70+
if not getattr(app, "device_address", None):
71+
app.device_address = "FF:FF:FF:FF:FF:FF"
72+
73+
ble.connect_by_device_address(app.device_address)
74+
```
75+
76+
## Discover device services and characteristics
77+
Wait a while, while device is connected. Start services discovery:
78+
79+
```python
80+
%%there -d 5
81+
ble.discover_services()
82+
```
83+
84+
Wait a while, while services discovered. Print connected device characteristics:
85+
86+
```python
87+
%%there -d 2
88+
print(type(ble.services))
89+
for service, characteristics in ble.services.items():
90+
print(f"Service {service} characteristics:")
91+
for characteristic in characteristics:
92+
print(f"\t*{characteristic}")
93+
```
94+
95+
## Read characteristic
96+
In this example, it is known that target device has characteristic
97+
with UUID = 16fe**0d01**-c111-11e3-b8c8-0002a5d5c51b
98+
This characteristic is readable, and always returns a string value: "test".
99+
100+
```python
101+
%%there
102+
characteristic = ble.services.search("0d01")
103+
print(f"Characteristic UUID found: {characteristic.getUuid().toString()}")
104+
print(f"Characteristic object: {characteristic}")
105+
# https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#getStringValue(int)
106+
print(f"Characteristic value is not available yet: {characteristic.getStringValue(0)}")
107+
108+
ble.read_characteristic(characteristic)
109+
```
110+
111+
Wait a while, and check characteristic value.
112+
**on_characteristic_read** message should appear in logs
113+
114+
```python
115+
%%there -d 2
116+
# https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic#getStringValue(int)
117+
print(characteristic.getStringValue(0))
118+
```

0 commit comments

Comments
 (0)