Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Thursday, July 15, 2021

Install PyQt5 for Python3 on Raspberry Pi OS

To install PyQt5 on Raspberry Pi OS, for Python3, enter the command:

$ sudo apt install python3-pyqt5

Currently, it's 5.11.3.



Tuesday, July 13, 2021

Install bluepy on Raspberry Pi, for Python3, and examples.

bluepy is a Python interface to Bluetooth LE on Linux.

To install bluepy on Raspberry Pi for Python3, enter the command:

$ sudo apt-get install python3-pip libglib2.0-dev
$ sudo pip3 install bluepy


ref:


bluepy examples:

There are two examples in bluepy, scanner and notification. Here how I modify it for Python3 working on Raspberry Pi, work with ESP32 BLE_uart example.


scanner.py
from bluepy.btle import Scanner, DefaultDelegate
class ScanDelegate(DefaultDelegate):
 def __init__(self):
 DefaultDelegate.__init__(self)
 def handleDiscovery(self, dev, isNewDev, isNewData):
 if isNewDev:
 print("Discovered device", dev.addr)
 elif isNewData:
 print("Received new data from", dev.addr)
scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(10.0)
for dev in devices:
 print("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))
 for (adtype, desc, value) in dev.getScanData():
 print(" %s = %s" % (desc, value))

notification.py
from bluepy import btle
class MyDelegate(btle.DefaultDelegate):
 def __init__(self):
 btle.DefaultDelegate.__init__(self)
 # ... initialise here
 def handleNotification(self, cHandle, data):
 print("\n- handleNotification -\n")
 print(data)
 # ... perhaps check cHandle
 # ... process 'data'
# Initialisation -------
p = btle.Peripheral("3c:71:bf:0d:dd:6a")
p.setDelegate( MyDelegate() )
# Setup to turn notifications on, e.g.
svc = p.getServiceByUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
ch = svc.getCharacteristics("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")[0]
# ch.write( setup_data )
setup_data = b"\x0100円"
p.writeCharacteristic(ch.valHandle+1, setup_data)
# Main loop --------
while True:
 if p.waitForNotifications(1.0):
 # handleNotification() was called
 continue
 print("Waiting...")
 # Perhaps do something else here


Next:

Thursday, April 8, 2021

ESP32/MicroPython server + Raspberry Pi/Python client, transmit image via WiFi TCP socket.

In this exercise, ESP32 (ESP32-DevKitC V4)/MicroPython play the role of AP, act as socket server. Raspberry Pi connect to ESP32 WiFi network, run Python code to load image, act as client and transmit the image to ESP32 server. The ESP32 server display the image on a 240*240 IPS (ST7789 SPI) LCD. It's is role reversed version of my previous exercise "Raspberry Pi/Python Server send image to ESP32/MicroPython Client via WiFi TCP socket".



protocol:

Client			|	 |	Server
(Raspberry Pi/Python)	|	 |	(ESP32/MicroPython)
			|	 |
			|	 |	Reset
			||	Setup AP
			|	|	Setup socket server
(connect to ESP32 WiFi)	|	|
			|	|
connect to ESP32 server	|	 |	accepted
			|<-- ACK ---|	
send the 0th line	|---------->|	display the 0th line
			|<-- ACK ---|	send ACK
send the 1st line	|---------->|	display the 1st line
			|<-- ACK ---|	send ACK
			.
			.
			.
send the 239th line	|---------->|	display the 239th line
			|<-- ACK ---|	send ACK
close socket		|  |	close socket
			|	 |
	
Server side:
(ESP32/MicroPython)

The ESP32 used is a ESP32-DevKitC V4, display is a 240*240 IPS (ST7789 SPI) LCD. Library setup and connection, refer to former post "ESP32 (ESP32-DevKitC V4)/MicroPython + 240*240 IPS (ST7789 SPI) using russhughes/st7789py_mpy lib".

upyESP32_ImgServer_AP_20210408a.py, MicroPython code run on ESP32. Save to ESP32 named main.py, such that it can run on power-up without host connected.
from os import uname
from sys import implementation
import machine
import network
import socket
import ubinascii
import utime
import st7789py as st7789
from fonts import vga1_16x32 as font
import ustruct as struct
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
 GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
ssid = "ssid"
AP_ssid = "ESP32"
password = "password"
serverIP = '192.168.1.30'
serverPort = 80
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
#spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
pin_spi2_sck = machine.Pin(18, machine.Pin.OUT)
pin_spi2_mosi = machine.Pin(23, machine.Pin.OUT)
pin_spi2_miso = machine.Pin(19, machine.Pin.IN)
spi2 = machine.SPI(2, sck=pin_spi2_sck, mosi=pin_spi2_mosi, miso=pin_spi2_miso,
 baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
 reset=pin_st7789_res,
 dc=pin_st7789_dc,
 xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print("MAC: " + mac)
print()
#init ESP32 as STA
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
utime.sleep(1)
def do_connect():
 global wlan
 print('connect to network...')
 display.fill(st7789.BLACK)
 display.text(font, "connect...", 10, 10)
 
 wlan.active(True)
 if not wlan.isconnected():
 print('...')
 wlan.connect(ssid, password)
 while not wlan.isconnected():
 pass
 
 print()
 print('network config:')
 print("interface's IP/netmask/gw/DNS addresses")
 #print(wlan.ifconfig())
 myIP = wlan.ifconfig()[0]
 print(myIP)
 
 display.fill(st7789.BLACK)
 display.text(font, myIP, 10, 10)
 
def do_setupAP():
 global wlan
 print('setup AP...')
 display.fill(st7789.BLACK)
 display.text(font, "setup AP...", 10, 10)
 utime.sleep(1)
 
 ap = network.WLAN(network.AP_IF)
 ap.active(True)
 ap.config(essid=AP_ssid, password=password)
 while ap.active() == False:
 pass
 
 print(ap.active())
 print()
 print('network config:')
 myIP = ap.ifconfig()
 print(myIP)
 
 display.fill(st7789.BLACK)
 display.text(font, myIP[0], 10, 10)
def do_setupServer():
 global wlan
 global display
 
 addr = socket.getaddrinfo('0.0.0.0', serverPort)[0][-1]
 s = socket.socket()
 s.bind(addr)
 s.listen(1)
 
 print('listening on', addr)
 display.text(font, ':'+str(serverPort), 10, 50)
 
 while True:
 print('waiting connection...')
 cl, addr = s.accept()
 cl.settimeout(5)
 print('client connected from:', addr)
 
 display.fill(st7789.BLACK)
 display.text(font, addr[0], 10, 10)
 
 cl.sendall('ACK')
 print('Firt ACK sent')
 
 display.set_window(0, 0, disp_width-1, disp_height-1)
 pin_st7789_dc.on()
 for j in range(disp_height):
 
 try:
 buff = cl.recv(disp_width*3)
 #print('recv ok: ' + str(j))
 except:
 print('except: ' + str(j))
 
 for i in range(disp_width):
 offset= i*3
 spi2.write(struct.pack(st7789._ENCODE_PIXEL,
 (buff[offset] & 0xf8) << 8 |
 (buff[offset+1] & 0xfc) << 3 |
 buff[offset+2] >> 3))
 #print('send ACK : ' + str(j))
 cl.sendall(bytes("ACK","utf-8"))
 #print('ACK -> : ' + str(j))
 utime.sleep(1)
 cl.close()
 print('socket closed')
 
#do_connect()
do_setupAP()
try:
 do_setupServer()
except:
 print('error')
 display.text(font, "Error", 10, 200)
finally:
 print('wlan.disconnect()')
 wlan.disconnect()
 
print('\n- bye -')
Client Side:
(Raspberry Pi/Python)

Connect Raspberry Pi to ESP32 WiFi network before run the Python code.

Load and send images with fixed resolution 240x240 (match with the display in client side) to server. My former post "min. version of RPi/Python Code to control Camera Module with preview on local HDMI" is prepared for this purpose to capture using Raspberry Pi Camera Module .

pyqTCP_ImgClient_20210408a.py
import sys
from pkg_resources import require
import time
import matplotlib.image as mpimg
import socket
#HOST = '192.168.1.34' # The server's hostname or IP address
HOST = '192.168.4.1'
PORT = 80 # The port used by the server
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QLabel,
 QFileDialog, QHBoxLayout, QVBoxLayout)
from PyQt5.QtGui import QPixmap, QImage
print(sys.version)
class AppWindow(QWidget):
 camPreviewState = False #not in Preview
 fileToUpload = ""
 def __init__(self):
 super().__init__()
 lbSysInfo = QLabel('Python:\n' + sys.version)
 vboxInfo = QVBoxLayout()
 vboxInfo.addWidget(lbSysInfo)
 #setup UI
 btnOpenFile = QPushButton("Open File", self)
 btnOpenFile.clicked.connect(self.evBtnOpenFileClicked)
 self.btnUpload = QPushButton("Upload", self)
 self.btnUpload.clicked.connect(self.evBtnUploadClicked)
 self.btnUpload.setEnabled(False)
 vboxCamControl = QVBoxLayout()
 vboxCamControl.addWidget(btnOpenFile)
 vboxCamControl.addWidget(self.btnUpload)
 vboxCamControl.addStretch()
 self.lbImg = QLabel(self)
 self.lbImg.resize(240, 240)
 self.lbImg.setStyleSheet("border: 1px solid black;")
 hboxCam = QHBoxLayout()
 hboxCam.addWidget(self.lbImg)
 hboxCam.addLayout(vboxCamControl)
 self.lbPath = QLabel(self)
 vboxMain = QVBoxLayout()
 vboxMain.addLayout(vboxInfo)
 vboxMain.addLayout(hboxCam)
 vboxMain.addWidget(self.lbPath)
 vboxMain.addStretch()
 self.setLayout(vboxMain)
 self.setGeometry(100, 100, 500,400)
 self.show()
 #wait client response in 3 byte len
 def wait_RESP(self, sock):
 #sock.settimeout(10)
 res = str()
 data = sock.recv(4)
 return data.decode("utf-8")
 def sendImageToServer(self, imgFile):
 print(imgFile)
 imgArray = mpimg.imread(imgFile)
 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
 s.connect((HOST, PORT))
 print(self.wait_RESP(s))
 for j in range(240):
 time.sleep(0.1)
 b = bytes(imgArray[j])
 #print('send img : ' + str(j))
 s.sendall(bytes(b))
 #print('img sent : ' + str(j))
 ans = self.wait_RESP(s)
 #print(ans + " : " + str(j))
 print('image sent finished')
 s.close()
 def evBtnUploadClicked(self):
 print("evBtnUploadClicked()")
 print(self.fileToUpload)
 self.sendImageToServer(self.fileToUpload)
 def evBtnOpenFileClicked(self):
 options = QFileDialog.Options()
 options |= QFileDialog.DontUseNativeDialog
 targetPath, _ = QFileDialog.getOpenFileName(
 self, 'Open file', '/home/pi/Desktop',
 'Image files (*.jpg)', options=options)
 if targetPath:
 print(targetPath)
 self.lbPath.setText(targetPath)
 with open(targetPath):
 pixmap = QPixmap(targetPath)
 #accept 240x240 image only
 if pixmap.width()==240 and pixmap.height()==240:
 self.lbImg.setPixmap(pixmap)
 self.btnUpload.setEnabled(True)
 self.fileToUpload = targetPath
 else:
 self.btnUpload.setEnabled(False)
 def evBtnOpenFileClickedX(self):
 targetPath="/home/pi/Desktop/image.jpg"
 print(targetPath)
 self.lbPath.setText(targetPath)
 try:
 with open(targetPath):
 pixmap = QPixmap(targetPath)
 self.lbImg.setPixmap(pixmap)
 #as a exercise, get some info from pixmap
 print('\npixmap:')
 print(pixmap)
 print(type(pixmap))
 print(str(pixmap.width()) + " : " + str(pixmap.height()))
 print()
 print('convert to Image')
 qim = pixmap.toImage()
 print(qim)
 print(type(qim))
 print()
 print('read a pixel from image')
 qrgb = qim.pixel(0, 0)
 print(hex(qrgb))
 print(type(qrgb))
 r, g, b = qRed(qrgb), qGreen(qrgb), qBlue(qrgb)
 print([hex(r), hex(g), hex(b)])
 print()
 except FileNotFoundError:
 print('File Not Found Error')
if __name__ == '__main__':
 print('run __main__')
 app = QApplication(sys.argv)
 window = AppWindow()
 sys.exit(app.exec_())
print("- bye -")
Remark:
At beginning, I tried to set ESP32 as STA, by calling do_connect(), connect to my home/mobile WiFi network. But the result is very unstable in: Pi client send 240 pixel but ESP32 server can't receive all. That's why you can find some commented debug code (using print()) in the program.

After then, set ESP32 as AP, Pi connect to ESP32 WiFi network. The result have great improved and very stable.




Wednesday, March 24, 2021

Raspberry Pi/Python Server send image to ESP32/MicroPython Client via WiFi TCP socket


In this exercise, Raspberry Pi/Python3 act as socket server, ESP32/MicroPython act as client connect to server via WiFi TCP. Once received, server (Pi/Python) send a image (240x240) to client (ESP32/MicroPython), then the client display the image on a 240*240 IPS (ST7789 SPI) LCD.


To make it more flexible, the image is in 240 batch of 240 pixel x 3 color (r, g, b).

protocol:

Server			|	|	Client
(Raspberry Pi/Python)	|	|	(ESP32/MicroPython)
			|	|
Start			|	|	Reset
			|	|
Setup as 		|	|
socketserver.TCPServer	|	|
			|	|
			|	|	Join the WiFi network
		|	|	Connect to server with socket
			|	|	
			|<-- ACK ---|	send ACK
send the 0th line	|---------->|	display the 0th line
			|<-- ACK ---|	send ACK
send the 1st line	|---------->|	display the 1st line
			.
			.
			.
send the 239th line	|---------->|	display the 239th line
			|<-- ACK ---|	send ACK
close socket		|	|	close socket
			|	|
wait next		|	|	bye	

Client side:

(ESP32/MicroPython)

The ESP32 used is a ESP32-DevKitC V4, display is a 240*240 IPS (ST7789 SPI) LCD. Library setup and connection, refer to former post "ESP32 (ESP32-DevKitC V4)/MicroPython + 240*240 IPS (ST7789 SPI) using russhughes/st7789py_mpy lib".

upyESP32_ImgClient_20210324c.py, MicroPython code run on ESP32. Modify ssid/password and serverIP for your WiFi network.
from os import uname
from sys import implementation
import machine
import network
import socket
import ubinascii
import utime
import st7789py as st7789
from fonts import vga1_16x32 as font
import ustruct as struct
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
 GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
ssid = "your ssid"
password = "your password"
serverIP = '192.168.1.30'
serverPort = 9999
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
 reset=pin_st7789_res,
 dc=pin_st7789_dc,
 xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print("MAC: " + mac)
print()
#init ESP32 as STA
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
utime.sleep(1)
def do_connect():
 global wlan
 print('connect to network...')
 display.fill(st7789.BLACK)
 display.text(font, "connect...", 10, 10)
 
 wlan.active(True)
 if not wlan.isconnected():
 print('...')
 wlan.connect(ssid, password)
 while not wlan.isconnected():
 pass
 
 print()
 print('network config:')
 print("interface's IP/netmask/gw/DNS addresses")
 print(wlan.ifconfig())
 
 display.fill(st7789.BLACK)
 display.text(font, "connected", 10, 10)
 
def do_scan():
 global wlan
 print('scan network...')
 wlan.active(True)
 for network in wlan.scan():
 print(network)
 
def do_connectServer():
 global wlan
 global display
 
 addr = socket.getaddrinfo(serverIP, serverPort)[0][-1]
 print(addr)
 s = socket.socket()
 s.connect(addr)
 
 print('---')
 display.fill(st7789.BLACK)
 display.text(font, "waiting...", 10, 10)
 print('Send ACK')
 s.sendall(bytes("ACK","utf-8"))
 
 display.set_window(0, 0, disp_width-1, disp_height-1)
 pin_st7789_dc.on()
 for j in range(disp_height):
 
 buff = s.recv(disp_width*3)
 for i in range(disp_width):
 offset= i*3
 spi2.write(struct.pack(st7789._ENCODE_PIXEL,
 (buff[offset] & 0xf8) << 8 |
 (buff[offset+1] & 0xfc) << 3 |
 buff[offset+2] >> 3))
 
 s.sendall(bytes("ACK","utf-8"))
 s.close()
 print('socket closed')
 
do_connect()
try:
 do_connectServer()
except:
 print('error')
 display.text(font, "Error", 10, 200)
finally:
 print('wlan.disconnect()')
 wlan.disconnect()
 
print('\n- bye -')

Server Side:
(Raspberry Pi/Python)

The server will send Desktop/image.jpg with fixed resolution 240x240 (match with the display in client side). My former post "min. version of RPi/Python Code to control Camera Module with preview on local HDMI" is prepared for this purpose to capture using Raspberry Pi Camera Module .

pyMyTCP_ImgServer_20210324c.py, Python3 code run on Raspberry Pi.
import socketserver
import platform
import matplotlib.image as mpimg
imageFile = '/home/pi/Desktop/image.jpg'
print("sys info:")
for info in platform.uname():
 print(info)
class MyTCPHandler(socketserver.BaseRequestHandler):
 #wait client response in 3 byte len
 def wait_RESPONSE(self, client):
 client.settimeout(10)
 res = str()
 data = client.recv(4)
 return data.decode("utf-8")
 def handle(self):
 msocket = self.request
 print("{} connected:".format(self.client_address[0]))
 imgArray = mpimg.imread(imageFile)
 self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
 print('first RESPONSE received')
 for j in range(240):
 b = bytes(imgArray[j])
 msocket.sendall(bytes(b))
 self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
 print('image sent finished')
 msocket.close()
if __name__ == "__main__":
 HOST, PORT = "localhost", 9999
 # Create the server, binding to localhost on port 9999
 #with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
 with socketserver.TCPServer(('', PORT), MyTCPHandler) as server:
 # Activate the server; this will keep running until you
 # interrupt the program with Ctrl-C
 server.serve_forever()
This socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server example is modify from Python 3 socketserver.TCPServer Example. I assume socketserver.TCPServer will handle Ctrl-C with port close. But in my test, SOMETIMES throw OSError of "Address already in use". In my practice, try pressing Ctrl-C in REPL/restart repeatedly.


Next:

Saturday, February 20, 2021

Pico/MicroPython + ESP-01S (AT Command) act as TCP Client connect to Raspberry Pi/Python TCP Server

This exercise program Raspberry Pi Pico in MicroPython, using ESP-01S (ESP8266) as WiFi co-processor, act as TCP Client.

The ESP-01S is flashed with AT command firmware, version:

AT version:1.7.4.0(May 11 2020 19:13:04)
SDK version:3.0.4(9532ceb)
compile time:May 27 2020 10:12:17
Bin version(Wroom 02):1.7.4
For the connection between Pico and ESP-01S, refer to previous post "Connect ESP-01S (ESP8266) to Raspberry Pi Pico/MicroPython, using AT Command".

The TCP server side is implemented using Python3 socketserver. It's copied and modified from Python Document > socketserver.

Both TCP server and client have to be connected in the same WiFi network.



mpyPico_ESP-01S_TCPclient_2021年02月21日a.py, client side run on Raspberry Pi Pico, programmed in MicroPython.
import uos
import machine
import utime
"""
Raspberry Pi Pico/MicroPython + ESP-01S exercise
ESP-01S(ESP8266) with AT-command firmware:
AT version:1.7.4.0(May 11 2020 19:13:04)
Pico send AT command to ESP-01S via UART,
- set in station mode
- join AP
- connect to server ip:port 9999
- send text and wait response
"""
#server port & ip hard-coded,
#have to match with server side setting
server_ip="192.168.12.147"
server_port=9999
print()
print("Machine: \t" + uos.uname()[4])
print("MicroPython: \t" + uos.uname()[3])
#indicate program started visually
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0) # onboard LED OFF/ON for 0.5/1.0 sec
utime.sleep(0.5)
led_onboard.value(1)
utime.sleep(1.0)
led_onboard.value(0)
uart0 = machine.UART(0, baudrate=115200)
print(uart0)
def sendCMD_waitResp(cmd, uart=uart0, timeout=2000):
 print("CMD: " + cmd)
 uart.write(cmd)
 waitResp(uart, timeout)
 print()
 
def waitResp(uart=uart0, timeout=2000):
 prvMills = utime.ticks_ms()
 resp = b""
 while (utime.ticks_ms()-prvMills)<timeout:
 if uart.any():
 resp = b"".join([resp, uart.read(1)])
 print("resp:")
 try:
 print(resp.decode())
 except UnicodeError:
 print(resp)
 
# send CMD to uart,
# wait and show response without return
def sendCMD_waitAndShow(cmd, uart=uart0):
 print("CMD: " + cmd)
 uart.write(cmd)
 while True:
 print(uart.readline())
 
def espSend(text="test", uart=uart0):
 sendCMD_waitResp('AT+CIPSEND=' + str(len(text)) + '\r\n')
 sendCMD_waitResp(text)
 
sendCMD_waitResp('AT\r\n') #Test AT startup
sendCMD_waitResp('AT+GMR\r\n') #Check version information
#sendCMD_waitResp('AT+RESTORE\r\n') #Restore Factory Default Settings
sendCMD_waitResp('AT+CWMODE?\r\n') #Query the Wi-Fi mode
sendCMD_waitResp('AT+CWMODE=1\r\n') #Set the Wi-Fi mode 1 = Station mode
#sendCMD_waitResp('AT+CWMODE=2\r\n') #Set the Wi-Fi mode 2 = S0ftAP mode
sendCMD_waitResp('AT+CWMODE?\r\n') #Query the Wi-Fi mode again
#sendCMD_waitResp('AT+CWLAP\r\n', timeout=10000) #List available APs
sendCMD_waitResp('AT+CWJAP="ssid","password"\r\n', timeout=5000) #Connect to AP
sendCMD_waitResp('AT+CIFSR\r\n') #Obtain the Local IP Address
#sendCMD_waitResp('AT+CIPSTART="TCP","192.168.12.147",9999\r\n')
sendCMD_waitResp('AT+CIPSTART="TCP","' +
 server_ip +
 '",' +
 str(server_port) +
 '\r\n')
espSend()
while True:
 print('Enter something:')
 msg = input()
 #sendCMD_waitResp('AT+CIPSTART="TCP","192.168.12.147",9999\r\n')
 sendCMD_waitResp('AT+CIPSTART="TCP","' +
 server_ip +
 '",' +
 str(server_port) +
 '\r\n')
 espSend(msg)
pyMyTCPServer_2021年02月21日a.py, run on Raspberry Pi, programmed in Python.
"""
ref:
https://docs.python.org/3/library/socketserver.html
"""
import socketserver
import platform
print("sys info:")
for info in platform.uname():
 print(info)
class MyTCPHandler(socketserver.BaseRequestHandler):
 """
 The request handler class for our server.
 It is instantiated once per connection to the server, and must
 override the handle() method to implement communication to the
 client.
 """
 def handle(self):
 # self.request is the TCP socket connected to the client
 self.data = self.request.recv(1024).strip()
 print("{} wrote:".format(self.client_address[0]))
 print(self.data)
 # just send back the same data, but upper-cased
 self.request.sendall(self.client_address[0].encode())
 self.request.sendall(self.data.upper())
 self.request.sendall(b'\r\n')
if __name__ == "__main__":
 HOST, PORT = "localhost", 9999
 # Create the server, binding to localhost on port 9999
 #with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
 with socketserver.TCPServer(('', PORT), MyTCPHandler) as server:
 # Activate the server; this will keep running until you
 # interrupt the program with Ctrl-C
 server.serve_forever()

Next:
~ TCP socket communication between (RPi Pico+ESP-01S) and ESP32 via WiFi

Friday, February 19, 2021

Python tips: print() text in color

Found a simple approach to print() text in color for Python REPL:

To make some of your text more readable, you can use ANSI escape codes to change the colour of the text output in your python program. A good use case for this is to to highlight errors.
~ read here: ozzmaker - Add Colour to Text in Python

Test on Raspberry Pi/Thonny with interpreter of MicroPython on Raspberry Pi Pico:



Wednesday, February 3, 2021

Raspberry Pi/Python remote control LED on Raspberry Pi Pico/MicroPython with HC-08 + ILI9341 SPI Display via Bluetooth

Raspberry Pi Pico/MicroPython exercise to work with HC-08 BLE 4.0 module, to communication with Raspberry Pi/Python. The ILI9341 SPI screen is used to display related information only. HC-08 connect to Pico via UART(0), as a BLE server. Once connected, Pico monitor the incoming data, if matched pattern of "#LEDON\r\n"/"#LEDOFF\r\n" received, it turn ON/OFF its onboard LED accordingly.

In the Raspberry Pi/Python, using bluepy library, act as client connect to Pico/HC-08 BLE server, setup a simple tkinter GUI, send "#LEDON\r\n"/"#LEDOFF\r\n" command if user click on the toggle button.

It's a group result of my previouse exercises:
~ Python on Raspberry Pi to read ESP32 BLE_server, using bluepy
~ Raspberry Pi Pico/MicroPython + 320x240 ILI9341 SPI Display, using jeffmer/micropython-ili9341 library
~ Raspberry Pi Pico/MicroPython + HC-08 BLE 4.0 UART Module

Connection between Raspberry Pi Pico and HC-08/ILI9341:

MicroPython/Python Code:

MicrcoPython code run on Raspberry Pi Pico, mpyPico_ili9341_HC08.py:

"""
Exercise on Raspberry Pi Pico/MicroPython
with 320x240 ILI9341 SPI Display
+ HC-08 Bluetooth UART Module(ver:HC-08 V3.1,2017年07月07日)
"""
from ili934xnew import ILI9341, color565
from machine import Pin, SPI
from micropython import const
import os
import glcdfont
import tt14
import tt24
import tt32
import time
#2 sec timeout is arbitrarily chosen
def sendCMD_waitResp(cmd, timeout=2000):
 print("CMD: " + cmd)
 uart.write(cmd)
 waitResp(timeout)
 print()
 
def waitResp(timeout=2000):
 prvMills = time.ticks_ms()
 resp = b""
 while (time.ticks_ms()-prvMills)<timeout:
 if uart.any():
 resp = b"".join([resp, uart.read(1)])
 print(resp)
 display.print(resp.decode('utf_8'))
def sendCMD_waitRespLine(cmd, timeout=2000):
 print("CMD: " + cmd)
 uart.write(cmd)
 waitRespLine(timeout)
 print()
 
def waitRespLine(timeout=2000):
 prvMills = time.ticks_ms()
 line = b""
 while (time.ticks_ms()-prvMills)<timeout:
 if uart.any():
 line = line+uart.readline()
 print(line)
 display.print(line.decode('utf_8'))
SCR_WIDTH = const(320)
SCR_HEIGHT = const(240)
SCR_ROT = const(2)
CENTER_Y = int(SCR_WIDTH/2)
CENTER_X = int(SCR_HEIGHT/2)
print(os.uname())
TFT_CLK_PIN = const(6)
TFT_MOSI_PIN = const(7)
TFT_MISO_PIN = const(4)
TFT_CS_PIN = const(13)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)
fonts = [glcdfont,tt14,tt24,tt32]
text = 'RPi Pico+ili9341+HC-08'
print(text)
#print uart info
#using UART(0)
#UART_TX = GP0
#UART_RX = GP1
uart = machine.UART(0, baudrate=9600,
 bits=8, parity=None, stop=1)
print(uart)
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0)
spi = SPI(
 0,
 baudrate=40000000,
 miso=Pin(TFT_MISO_PIN),
 mosi=Pin(TFT_MOSI_PIN),
 sck=Pin(TFT_CLK_PIN))
print(spi)
display = ILI9341(
 spi,
 cs=Pin(TFT_CS_PIN),
 dc=Pin(TFT_DC_PIN),
 rst=Pin(TFT_RST_PIN),
 w=SCR_WIDTH,
 h=SCR_HEIGHT,
 r=SCR_ROT)
display.erase()
display.set_pos(0,0)
#indicate program started visually
display.set_font(tt24)
display.print(text)
time.sleep(1)
"""
for i in range(20):
 display.scroll(1)
 time.sleep(0.01)
"""
led_onboard.value(1)
time.sleep(0.5)
led_onboard.value(0)
"""
for i in range(20):
 display.scroll(-1)
 time.sleep(0.01)
"""
#-----------------------------------
#clear bufer in UART
display.set_font(tt14)
waitResp()
sendCMD_waitResp("AT")
sendCMD_waitRespLine("AT+RX")
display.set_font(tt24)
while True:
 char = uart.read(1)
 print(char)
 
 if char == b'#':
 print("match")
 bleCmd = uart.readline()
 if bleCmd == b'LEDON\r\n':
 led_onboard.value(1)
 display.fill_rectangle(0, 280, 200, 20, color565(0, 0, 0))
 display.set_pos(0, 280)
 display.print("- LED ON -")
 print("- LED ON -")
 if bleCmd == b'LEDOFF\r\n':
 led_onboard.value(0)
 display.fill_rectangle(0, 280, 200, 20, color565(0, 0, 0))
 display.set_pos(0, 280)
 display.print("- LED OFF -")
 print("- LED OFF -")
 
 else:
 print(bleCmd)
 #display.print(char.decode('utf_8'))
print("- bye-")

Python code run on Raspberry Pi 4, pyBLE_Pico_HC08.py:

from bluepy import btle
import time
import tkinter as tk
HC08_Char = None
def toggle():
 if toggle_btn.config('relief')[-1] == 'sunken':
 toggle_btn.config(relief="raised")
 HC08_Char.write(b'#LEDOFF\r\n')
 toggle_btn['text'] = 'Turn LED ON'
 else:
 toggle_btn.config(relief="sunken")
 HC08_Char.write(b'#LEDON\r\n')
 toggle_btn['text'] = 'Turn LED OFF'
MAC = "F8:33:31:E2:A0:42"
SERVICE_UUID = "FFE0"
CHARACTERISTIC_UUID = "FFE1"
print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)
print("\n--- dev.services -------------------")
for svc in dev.services:
 print(str(svc))
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)
print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())
#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
for char in characteristics:
 print("----------")
 print(type(char))
 print(char)
 print(char.uuid)
 if(char.uuid == CHARACTERISTIC_UUID ):
 print("=== !CHARACTERISTIC_UUID matched! ==")
 HC08_Char = char
 print(char)
 print(dir(char))
 print(char.getDescriptors)
 print(char.propNames)
 print(char.properties)
 print(type(char.read()))
 print(char.read())
if HC08_Char != None:
 for i in range(3):
 HC08_Char.write(b'#LEDON\r\n')
 time.sleep(0.5)
 HC08_Char.write(b'#LEDOFF\r\n')
 time.sleep(0.5)
 root = tk.Tk()
 label = tk.Label( root, text="Toggle button to Turn ON/OFF the Pico LED via HC-08/BLE")
 label.pack(pady=10)
 toggle_btn = tk.Button(text="Turn LED ON", width=12, relief="raised", command=toggle)
 toggle_btn.pack(pady=10)
 root.geometry("500x200")
 #Place tkinter window center
 root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
 root.title("helloraspberrypi.blogspot.com")
 root.mainloop()
else:
 print("Target HC-08 Not found!!!")
dev.disconnect()
print("--- bye ---")

Next:
~ ESP32 BLE Client remote control Raspberry Pi Pico/HC-08 via Bluetooth, almost same function to this exercise have ESP32 BLE client to replace Raspberry Pi/Python.

~ More exercise for Raspberry Pi Pico


Sunday, January 24, 2021

BLE Notification example: Python/Raspberry Pi read notification from ESP32 BLE server to display Analog Input

It's a Python example run on Raspberry Pi, using libraries bluepy/matplotlib, connect to ESP32 BLE Server (run on ESP32-DevKitC V4), handle notification, and plot the value graphically. It's modified from last exercise of Python/Raspberry Pi handle Notification from ESP32 BLE_notify example.


pyBLE_test_waitNotification_AIN.py
# Python3 example on Raspberry Pi to handle notification from
# ESP32 BLE_notify example.
#
# To install bluepy for Python3:
# $ sudo pip3 install bluepy
from bluepy import btle
import matplotlib.pyplot as plt
value = [0]*30
plt.ylim([0, 256])
plt.plot(value)
plt.draw()
plt.pause(0.01)
class MyDelegate(btle.DefaultDelegate):
 def __init__(self):
 btle.DefaultDelegate.__init__(self)
 # ... initialise here
 def handleNotification(self, cHandle, data):
 # ... perhaps check cHandle
 # ... process 'data'
 #print(type(data))
 #print(dir(data))
 print(data)
 print(data[0])
 
 value.pop(0)
 value.append(data[0])
 plt.clf()
 plt.ylim([0, 256])
 plt.plot(value)
 plt.draw()
 plt.pause(0.01)
 
# Initialisation -------
address = "24:0a:c4:e8:0f:9a"
service_uuid = "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
char_uuid = "beb5483e-36e1-4688-b7f5-ea07361b26a8"
p = btle.Peripheral(address)
p.setDelegate(MyDelegate())
# Setup to turn notifications on, e.g.
svc = p.getServiceByUUID(service_uuid)
ch = svc.getCharacteristics(char_uuid)[0]
"""
setup_data for bluepy noification-
"""
setup_data = b"\x01\x00"
#ch.write(setup_data)
p.writeCharacteristic(ch.valHandle + 1, setup_data)
ch_data = p.readCharacteristic(ch.valHandle + 1)
print(type(ch_data))
print(ch_data)
print("=== Main Loop ===")
while True:
 if p.waitForNotifications(1.0):
 # handleNotification() was called
 continue
 #print("Waiting...")
 # Perhaps do something else here


Wednesday, January 20, 2021

Python/Raspberry Pi handle Notification from ESP32 BLE_notify example

It's a Python3 example code (using bluepy library) run on Raspberry Pi, connect to ESP32 BLE server (programmed with BLE_notify example), and handle the Notification from ESP32.

Where address, service_uuid and char_uuid have to match with ESP32 side.

pyBLE_test_waitNotification_20210120a.py
"""
ref:
bluepy Documentation: Working with notifications
http://ianharvey.github.io/bluepy-doc/notifications.html
"""
# Python3 example on Raspberry Pi to handle notification from
# ESP32 BLE_notify example.
#
# To install bluepy for Python3:
# $ sudo pip3 install bluepy
from bluepy import btle
class MyDelegate(btle.DefaultDelegate):
 def __init__(self):
 btle.DefaultDelegate.__init__(self)
 # ... initialise here
 def handleNotification(self, cHandle, data):
 # ... perhaps check cHandle
 # ... process 'data'
 #print(type(data))
 #print(dir(data))
 print(data)
 print(data[0])
# Initialisation -------
address = "24:0a:c4:e8:0f:9a"
service_uuid = "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
char_uuid = "beb5483e-36e1-4688-b7f5-ea07361b26a8"
p = btle.Peripheral(address)
p.setDelegate(MyDelegate())
# Setup to turn notifications on, e.g.
svc = p.getServiceByUUID(service_uuid)
ch = svc.getCharacteristics(char_uuid)[0]
"""
print(type(ch))
print(ch)
print(dir(ch))
peripheral = ch.peripheral
print(type(peripheral))
print(peripheral)
propNames = ch.propNames
print(type(propNames))
print(propNames)
properties = ch.properties
print(type(properties))
print(properties)
"""
"""
Remark for setup_data for bluepy noification-
Actually I don't understand how come setup_data = b"\x01\x00",
and ch.valHandle + 1.
Just follow suggestion by searching in internet:
https://stackoverflow.com/questions/32807781/
ble-subscribe-to-notification-using-gatttool-or-bluepy
"""
setup_data = b"\x01\x00"
#ch.write(setup_data)
p.writeCharacteristic(ch.valHandle + 1, setup_data)
ch_data = p.readCharacteristic(ch.valHandle + 1)
print(type(ch_data))
print(ch_data)
print("=== Main Loop ===")
while True:
 if p.waitForNotifications(1.0):
 # handleNotification() was called
 continue
 #print("Waiting...")
 # Perhaps do something else here

Next:

Sunday, January 17, 2021

Python on Raspberry Pi to read ESP32 BLE_server, using bluepy

This Python exercise run on Raspberry Pi using bluepy library, read ESP32 (Arduino Framework) BLE_server example (with BLE_client also) .

To install bluepy for Python3, enter the command:
$ sudo pip3 install bluepy

Python code, pyBLE_test_20210117a.py

from bluepy import btle
MAC = "24:0a:c4:e8:0f:9a"
SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
CHARACTERISTIC_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8"
print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)
print("\n--- dev.services -------------------")
for svc in dev.services:
 print(str(svc))
 
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)
print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())
#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
for char in characteristics:
 print("----------")
 print(type(char))
 print(char)
 print(char.uuid)
 if(char.uuid == CHARACTERISTIC_UUID ):
 print("=== !CHARACTERISTIC_UUID matched! ==")
 print(char)
 print(dir(char))
 print(char.getDescriptors)
 print(char.propNames)
 print(char.properties)
 print(type(char.read()))
 print(char.read())
 
#print("=== dev ============================")
#print(dir(dev))
#print("=== service ========================")
#print(dir(service))


Tuesday, December 29, 2020

Raspberry Pi/Python as Bluetooth classic client, bi-direction communication with ESP32

Raspberry Pi/Python act as GUI Bluetooth classic client, using tkinter/pybluez:
Connect to bluetooth classic server with hard-coded MAC.
User enter text to sent on bottom Text Frame, send to server.
Display the data received from server on upper Text frame.

The server side, run on ESP32 (NodeMCU ESP-32S), with SPI ST7735 IPS screen. It echo back received data. ESP32 (Arduino framework) code: Arduino-er: ESP-32S as Bluetooth classic Server, bi-direction communication with Raspberry Pi/Python.

Python code, pySPPClient.py.

import sys
from tkinter import *
from bluetooth import *
from threading import Thread
import time
rqsStopBtHandler = False
buf_size = 255
def btHandler():
 global rqsStopBtHandler
 rqsStopBtHandler = False
 
 print("btHandler Started")
 
 #Set sock.settimeout(),
 #to prevent program blocked by sock.recv()
 #and cannot end btHandler
 sock.settimeout(1.0)
 while rqsStopBtHandler!=True:
 try:
 datarx = sock.recv(buf_size)
 datarxToStr = datarx.decode("utf-8")
 print(datarxToStr)
 textCenter.insert(INSERT, datarxToStr)
 except Exception:
 continue
 
 print("btHandler End")
 
def startBtHandler():
 btThread = Thread(target=btHandler)
 btThread.start()
 
def close_window():
 global rqsStopBtHandler
 rqsStopBtHandler = True
 sock.close()
 print("Socket closed")
 print("Window closed")
 root.destroy()
def cmdSend():
 stringSent = textBottom.get(1.0, END)
 print(stringSent)
 sock.send(stringSent)
 #sock.send("\n")
 print("- Sent")
 
#===============================================
#Prepare Bluetooth Classic
print("Python version: ")
print(sys.version)
print("tkinter version: ", TkVersion)
print("=============================")
print("Connect to ESP32 Bluetooth Classic SPP Server")
#addr = "24:0A:C4:E8:0F:9A"
addr = "3C:71:BF:0D:DD:6A"
print(addr)
service_matches = find_service( address = addr )
if len(service_matches) == 0:
 print("couldn't find the ESP32 Bluetooth Classic SPP service")
 sys.exit(0)
 
for s in range(len(service_matches)):
 print("\nservice_matches: [" + str(s) + "]:")
 print(service_matches[s])
 
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
port=1
print("connecting to \"%s\" on %s, port %s" % (name, host, port))
# Create the client socket
sock=BluetoothSocket(RFCOMM)
sock.connect((host, port))
print("connected")
#===============================================
#Prepare GUI
root = Tk()
root.configure(bg="darkgray") 
root.wm_title("SPP Client")
root.protocol("WM_DELETE_WINDOW", close_window)
rootFrame = Frame(root)
rootFrame.pack()
labelTitle = Label(root,
 text="helloraspberrypi.blogspot.com",
 font=("Helvetica", 18),
 fg="White", bg="darkgray")
labelTitle.pack()
frameCenter = Frame(root, bg="lightgray")
frameCenter.pack()
textCenter= Text(frameCenter, width=26, height=10, font=("Helvetica", 18))
textCenter.pack(padx=10,pady=5)
frameBottom = Frame(root, bg="gray")
frameBottom.pack(expand=True, fill='both')
textBottom = Text(frameBottom, width=26, height=10, font=("Helvetica", 18))
textBottom.insert(INSERT, "Enter text here")
textBottom.pack(padx=10,pady=5)
buttonSend = Button(frameBottom, text="Send", command=cmdSend)
buttonSend.pack(padx=10,pady=5)
startBtHandler()
root.mainloop()
print("--- bye ---")

Related:

Friday, December 25, 2020

Raspberry Pi/Python remote control ESP32/Servos via Bluetooth Classic

Last exercise show how Python (on Raspberry Pi) Bluetooth communicate with ESP32 SerialToSerialBT, using pybluez. This exercise extended to send simple single character command to ESP32 via Bluetooth Classic, to control remote servos; with GUI using Tkinter.


pyBTServoClient_20201226.py, for Python3.
import sys
from tkinter import *
from bluetooth import *
print("Python version: ")
print(sys.version)
print("tkinter version: ", TkVersion)
print("=============================");
print("Connect to ESP BT Servo Server")
addr = "24:0A:C4:E8:0F:9A"
print(addr)
service_matches = find_service( address = addr )
if len(service_matches) == 0:
 print("couldn't find the ESP32 BT Servo service")
 sys.exit(0)
 
for s in range(len(service_matches)):
 print("\nservice_matches: [" + str(s) + "]:")
 print(service_matches[s])
 
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
port=1
print("connecting to \"%s\" on %s, port %s" % (name, host, port))
# Create the client socket
sock=BluetoothSocket(RFCOMM)
sock.connect((host, port))
print("connected")
def close_window():
 sock.close()
 print("Socket closed")
 print("Window closed")
 root.destroy()
#prepare GUI
root = Tk()
root.geometry("380x200")
root.configure(bg="lightgray") 
root.wm_title("Bluetooth Servo Client")
root.protocol("WM_DELETE_WINDOW", close_window)
CMD_ORG = 'O'
CMD_XDEC = 'A'
CMD_XDEC10 = 'B'
CMD_XINC = 'C'
CMD_XINC10 = 'D'
CMD_YDEC = 'E'
CMD_YDEC10 = 'F'
CMD_YINC = 'G'
CMD_YINC10 = 'H'
def cmdO():
 sock.send(CMD_ORG)
 print("0, 0")
def cmdXdec():
 sock.send(CMD_XDEC)
 print("X-")
 
def cmdXdec10():
 sock.send(CMD_XDEC10)
 print("X-10")
def cmdXinc():
 sock.send(CMD_XINC)
 print("X+")
 
def cmdXinc10():
 sock.send(CMD_XINC10)
 print("X+10")
 
def cmdYdec():
 sock.send(CMD_YDEC)
 print("Y-")
 
def cmdYdec10():
 sock.send(CMD_YDEC10)
 print("Y-10")
def cmdYinc():
 sock.send(CMD_YINC)
 print("Y+")
 
def cmdYinc10():
 sock.send(CMD_YINC10)
 print("Y+10")
ButtonO = Button(root, text="0", command = cmdO, width=6)
ButtonXdec = Button(root, text="X-", command = cmdXdec, width=6)
ButtonXinc = Button(root, text="X+", command = cmdXinc, width=6)
ButtonYdec = Button(root, text="Y-", command = cmdYdec, width=6)
ButtonYinc = Button(root, text="Y+", command = cmdYinc, width=6)
ButtonXdec10 = Button(root, text="X-10", command = cmdXdec10, width=6)
ButtonXinc10 = Button(root, text="X+10", command = cmdXinc10, width=6)
ButtonYdec10 = Button(root, text="Y-10", command = cmdYdec10, width=6)
ButtonYinc10 = Button(root, text="Y+10", command = cmdYinc10, width=6)
ButtonO.grid(row=2, column=2)
ButtonXdec.grid(row=2, column=1)
ButtonXinc.grid(row=2, column=3)
ButtonYdec.grid(row=3, column=2)
ButtonYinc.grid(row=1, column=2)
ButtonXdec10.grid(row=2, column=0)
ButtonXinc10.grid(row=2, column=4)
ButtonYdec10.grid(row=4, column=2)
ButtonYinc10.grid(row=0, column=2)
root.mainloop()
print("\n--- bye ---\n")
The ESP32 code (run on Arduino framework) is in my another blog's post: Arduino-er - ESP32 receive Bluetooth Classic command from Raspberry Pi/Python, to control Servos.

Next:

Saturday, December 19, 2020

Python (on Raspberry Pi) Bluetooth communicate with ESP32 SerialToSerialBT, using pybluez

It's a simple Python example using pybluez extension module, run on Raspberry Pi 4/Raspberry Pi OS, to communicate with ESP32 SerialToSerialBT example.

pybluez (or https://github.com/pybluez/pybluez)is a Python extension module allowing access to system Bluetooth resources.

Install pybluez for Python3, enter the command in Terminal:

$ sudo pip3 install pybluez

Copy and modify pybluez/examples/simple/rfcomm-client.py in Raspberry Pi Thonny.

It's my modified version, pyBTSimpleClient.py

from bluetooth import *
def input_and_send():
 print("\nType something\n")
 while True:
 data = input()
 if len(data) == 0: break
 sock.send(data)
 sock.send("\n")
 
def rx_and_echo():
 sock.send("\nsend anything\n")
 while True:
 data = sock.recv(buf_size)
 if data:
 print(data)
 sock.send(data)
 
#MAC address of ESP32
addr = "24:0A:C4:E8:0F:9A"
#uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
#service_matches = find_service( uuid = uuid, address = addr )
service_matches = find_service( address = addr )
buf_size = 1024;
if len(service_matches) == 0:
 print("couldn't find the SampleServer service =(")
 sys.exit(0)
for s in range(len(service_matches)):
 print("\nservice_matches: [" + str(s) + "]:")
 print(service_matches[s])
 
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
port=1
print("connecting to \"%s\" on %s, port %s" % (name, host, port))
# Create the client socket
sock=BluetoothSocket(RFCOMM)
sock.connect((host, port))
print("connected")
#input_and_send()
rx_and_echo()
sock.close()
print("\n--- bye ---\n")
How it run on Raspberry Pi 4/Raspberry Pi OS, communicate with ESP32 (ESP32-DevKitC V4) SerialToSerialBT example. The code in ESP32 side is in my another blog Arduino-er: ESP32 Bluetooth serial example.

Next:


ImportError: libbluetooth.so.3


If you reported with error of:
ImportError: libbluetooth.so.3: cannot open shared object file: No such file or directory

Install required library by entering the command in Terminal:
$ sudo apt install bluetooth bluez libbluetooth-dev


Thursday, November 5, 2020

psutil, process and system utilities for Python

psutil (process and system utilities) is a cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network, sensors) in Python.

In my trial on Ubuntu Desktop for Raspberry Pi, it's installed by default.

Links:
- GitHub - giampaolo /psutil
- psutil documentation



Install Thonny on Ubuntu for Raspberry Pi

Thonny is a very great cross-platform Python IDE.

To install Thonny on Ubuntu Desktop for Raspberry Pi, simple enter the command in Terminal:

$ sudo apt install thonny

After installed, you can enter "thonny" in Terminal, or search "thonny" in Activities.


Monday, January 28, 2019

A friendly video tutorial to get started with TensorFlow and Deep Learning

A friendly introduction to Deep Learning, taught at the beginner level. Work through introductory exercises across several domains - including computer vision, natural language processing, and structured data classification. Introduce TensorFlow - the world’s most popular open source machine learning library - preview the latest APIs (including Eager Execution), discuss best practices, and point you to recommended educational resources you can use to learn more.

Getting Started with TensorFlow and Deep Learning | SciPy 2018 Tutorial | Josh Gordon

Monday, June 27, 2016

picamera updated 1.11


Picamera updated 1.11, now support Camera V2. If you not yet updated, run the command to update:
$ sudo apt-get update
$ sudo apt-get upgrade

Suggested to update firmware also:
$ sudo rpi-update


Release 1.11 (2016年06月19日) Change log (https://picamera.readthedocs.io/en/release-1.11/changelog.html):

1.11 on the surface consists mostly of enhancements, but underneath includes a major re-write of picamera’s core:

  • Direct capture to buffer-protocol objects, such as numpy arrays (#241)
  • Add request_key_frame() method to permit manual request of an I-frame during H264 recording; this is now used implicitly by split_recording() (#257)
  • Added timestamp attribute to query camera’s clock (#212)
  • Added framerate_delta to permit small adjustments to the camera’s framerate to be performed “live” (#279)
  • Added clear() and copy_to() methods to PiCameraCircularIO (#216)
  • Prevent setting attributes on the main PiCamera class to ease debugging in educational settings (#240)
  • Due to the core re-writes in this version, you may require cutting edge firmware (sudo rpi-update) if you are performing unencoded captures, unencoded video recording, motion estimation vector sampling, or manual sensor mode setting.
  • Added property to control preview’s resolution separately from the camera’s resolution (required for maximum resolution previews on the V2 module - #296).

There are also several bug fixes:

  • Fixed basic stereoscopic operation on compute module (#218)
  • Fixed accessing framerate as a tuple (#228)
  • Fixed hang when invalid file format is specified (#236)
  • Fixed multiple bayer captures with capture_sequence() and capture_continuous() (#264)
  • Fixed usage of “falsy” custom outputs with motion_output (#281)
Many thanks to the community, and especially thanks to 6by9 (one of the firmware developers) who’s fielded seemingly endless questions and requests from me in the last couple of months!


Hardware Limits (http://picamera.readthedocs.io/en/release-1.11/fov.html#hardware-limits):

The are additional limits imposed by the GPU hardware that performs all image and video processing:

  • The maximum resolution for MJPEG recording depends partially on GPU memory. If you get “Out of resource” errors with MJPEG recording at high resolutions, try increasing gpu_mem in /boot/config.txt.
  • The maximum horizontal resolution for default H264 recording is 1920. Any attempt to recording H264 video at higher horizontal resolutions will fail.
  • However, H264 high profile level 4.2 has slightly higher limits and may succeed with higher resolutions.
  • The maximum resolution of the V2 camera can cause issues with previews. Currently, picamera runs previews at the same resolution as captures (equivalent to -fp in raspistill). You may need to increase gpu_mem in /boot/config.txt to achieve full resolution operation with the V2 camera module.
  • The maximum framerate of the camera depends on several factors. With overclocking, 120fps has been achieved on a V2 module but 90fps is the maximum supported framerate.
  • The maximum exposure time is currently 6 seconds on the V1 camera module, and 10 seconds on the V2 camera module. Remember that exposure time is limited by framerate, so you need to set an extremely slow framerate before setting shutter_speed.



Monday, June 20, 2016

Raspberry Pi display on 128x64 I2C OLED with SSD1306, using Python


This post show how to install rm-hull/ssd1306 on Raspberry Pi, and run the example to display on 0.96" 128x64 I2C OLED with SSD1306 driver, using Python.


rm-hull/ssd1306 interfacing OLED matrix displays with the SSD1306 (or SH1106) driver in Python using I2C on the Raspberry Pi.

Before install rm-hull/ssd1306, we have to enable I2C on the Raspberry Pi.

Connect a 0.96" 128x64 I2C OLED to Raspberry Pi 2 as shown:
3V3, GND, SDA and SCL respectively.
(my OLED support both 3.3V and 5V)

Download rm-hull/ssd1306 with:
$ wget https://github.com/rm-hull/ssd1306/archive/master.zip

Install the library, switch to the unpacked download folder:
$ sudo python setup.py install

Install some packages:

$ sudo apt-get install i2c-tools python-smbus python-pip
$ sudo pip install pillow

That's, now you can try the example, refer to the video.


Remark@2017年05月07日:

Somebody commented with error of:
error in luma.oled setup command : 'extras_require' must be a dictionary whose values are strings or lists of strings containing valid project/version requirement specifiers.

I google to found that it may be because of the version of setuptools.

Install and upgrade setuptools:
$ sudo -H pip install --upgrade pip setuptools

(reference: https://github.com/rm-hull/luma.examples/issues/44)


Related:
- NodeMCU/ESP8266 + OLED 0.96" 128x64 I2C SSD1306 using esp8266-oled-ssd1306 library


Updated@2017年05月14日:
The driver renamed rm-hull/luma.oled, and updated to support SSD1306 / SSD1322 / SSD1325 / SSD1331 / SH1106 OLED.

Friday, April 29, 2016

Python on Raspberry Pi + Camera Module to take photos for timelapse

I finalized my Python exercise to take photos and generate timelapse mp4, run on Raspberry Pi (Raspbian Jessie) with Camera Module installed.


To run the Python on update Raspbian Jessie (2016年03月18日), we have to install python-imaging-tk:
$ sudo apt-get install python-imaging-tk

In you desktop, create a shell script, doLapse.sh, and make it executable to run the Python code. Such that you can easy run it.

doLapse.sh
cd ~/pyLapse
python2 myPiLapse.py

The myPiLapse.py is the Python script (Python 2) to take photos. Select "Timelapse" tab and click the "Start TimeLapse" button to start and click the "Stop TimeLapse" button to stop. All the photos will be save in sub-directory named with timestamp.

myPiLapse.py
import picamera
import Tkinter as tk
import ttk
import time
from PIL import ImageTk, Image
from threading import Thread
import io
import sys
from pkg_resources import require
from fractions import Fraction
from time import sleep
import tkFont
import os
#reference:
# http://picamera.readthedocs.org/en/latest/api_camera.html
RQS_0=0
RQS_QUIT=1
RQS_CAPTURE=2
RQS_STARTLAPSE = 3
RQS_STOPLAPSE = 4
RQS_LAPSEEND = 5
rqs=RQS_0
rqsUpdateSetting=True
LAPSE_RQS_0 = 0
LAPSE_RQS_STOP = 1
lapse_rqs = LAPSE_RQS_0
PREFIX_IMAGE = "img_"
PREFIX_LAPSE = "lapse_"
prefix = PREFIX_IMAGE
def camHandler():
 global rqs
 rqs = RQS_0
 timelapsing = False
 
 camera = picamera.PiCamera()
 #stream = io.BytesIO()
 #set default
 camera.sharpness = 0
 camera.contrast = 0
 camera.brightness = 50
 camera.saturation = 0
 camera.ISO = 0
 camera.video_stabilization = False
 camera.exposure_compensation = 0
 camera.exposure_mode = 'auto'
 camera.meter_mode = 'average'
 camera.awb_mode = 'auto'
 camera.image_effect = 'none'
 camera.color_effects = None
 #camera.rotation = 0
 camera.rotation = 270
 camera.hflip = False
 camera.vflip = False
 camera.crop = (0.0, 0.0, 1.0, 1.0)
 #camera.resolution = (1024, 768)
 camera.resolution = (400, 300)
 #end of set default
 #camera.start_preview()
 while rqs != RQS_QUIT:
 #check if need update setting
 global rqsUpdateSetting
 if ((rqsUpdateSetting == True) and (timelapsing == False)):
 rqsUpdateSetting = False
 camera.sharpness = scaleSharpness.get()
 camera.contrast = scaleContrast.get()
 camera.brightness = scaleBrightness.get()
 camera.saturation = scaleSaturation.get()
 camera.exposure_compensation = scaleExpCompensation.get()
 camera.iso = varIso.get()
 camera.drc_strength = varDrc.get()
 camera.exposure_mode = varExpMode.get()
 camera.meter_mode = varMeterMode.get()
 camera.rotation = varRotation.get()
 camera.vflip = varVFlip.get()
 camera.hflip = varHFlip.get()
 camera.image_denoise = varDenoise.get()
 awb_mode_setting = varAwbMode.get()
 labelAwbVar.set(awb_mode_setting)
 camera.awb_mode = awb_mode_setting
 if awb_mode_setting == "off":
 gr = scaleGainRed.get()
 gb = scaleGainBlue.get()
 gAwb = (gr, gb)
 camera.awb_gains = gAwb
 labelAwbVar.set(awb_mode_setting + " : "
 + str(gAwb))
 image_effect_setting = varImageEffect.get()
 labelImageEffectVar.set(image_effect_setting)
 camera.image_effect = image_effect_setting
 if image_effect_setting == 'solarize':
 if cbSolarize_yuv_Var.get():
 yuv = 1
 else:
 yuv = 0
 solarize_para = (
 yuv,
 scSolarize_x0_Var.get(),
 scSolarize_y0_Var.get(),
 scSolarize_y1_Var.get(),
 scSolarize_y2_Var.get())
 labelImageEffectVar.set(image_effect_setting + " " + str(solarize_para))
 camera.image_effect_params = solarize_para
 elif image_effect_setting == 'colorpoint':
 camera.image_effect_params = quadrantVar.get()
 labelImageEffectVar.set(image_effect_setting + " " + str(quadrantVar.get()))
 elif image_effect_setting == 'colorbalance':
 colorbalance_para = (
 scColorbalance_lens_Var.get(),
 scColorbalance_r_Var.get(),
 scColorbalance_g_Var.get(),
 scColorbalance_b_Var.get(),
 scColorbalance_u_Var.get(),
 scColorbalance_v_Var.get())
 labelImageEffectVar.set(image_effect_setting + " " + str(colorbalance_para))
 camera.image_effect_params = colorbalance_para
 elif image_effect_setting == 'colorswap':
 labelImageEffectVar.set(image_effect_setting + " " + str(cbColorswap_dir_Var.get()))
 camera.image_effect_params = cbColorswap_dir_Var.get()
 elif image_effect_setting == 'posterise':
 labelImageEffectVar.set(image_effect_setting + " " + str(scPosterise_steps_Var.get()))
 camera.image_effect_params = scPosterise_steps_Var.get()
 elif image_effect_setting == 'blur':
 labelImageEffectVar.set(image_effect_setting + " " + str(scBlur_size_Var.get()))
 camera.image_effect_params = scBlur_size_Var.get()
 elif image_effect_setting == 'film':
 film_para = (
 scFilm_strength_Var.get(),
 scFilm_u_Var.get(),
 scFilm_v_Var.get())
 labelImageEffectVar.set(image_effect_setting + " " + str(film_para))
 camera.image_effect_params = film_para
 elif image_effect_setting == 'watercolor':
 if cbWatercolor_uv_Var.get():
 watercolor_para = (
 scWatercolor_u_Var.get(),
 scWatercolor_v_Var.get())
 labelImageEffectVar.set(image_effect_setting + " " + str(watercolor_para))
 camera.image_effect_params = watercolor_para
 else:
 watercolor_para = ()
 labelImageEffectVar.set(image_effect_setting + " " + str(watercolor_para))
 camera.image_effect_params = watercolor_para
 if rqs == RQS_CAPTURE:
 global prefix
 print("Capture")
 rqs=RQS_0
 timeStamp = time.strftime("%Y%m%d-%H%M%S")
 jpgFile=prefix+timeStamp+'.jpg'
 
 #camera.resolution = (2592, 1944) #set photo size
 varRes = varResolution.get()
 if varRes == '640x480':
 settingResolution = (640, 480)
 elif varRes == '800x600':
 settingResolution = (800, 600)
 elif varRes == '1280x720':
 settingResolution = (1280, 720)
 elif varRes == '1296x730':
 settingResolution = (1296, 730)
 elif varRes == '1296x972':
 settingResolution = (1296, 972)
 elif varRes == '1600x1200':
 settingResolution = (1600, 1200)
 elif varRes == '1920x1080':
 settingResolution = (1920, 1080)
 else:
 settingResolution = (2592, 1944)
 camera.resolution = settingResolution
 shutterSpeedSetting = varShutterSpeed.get()
 settingQuality = varQuality.get()
 
 if shutterSpeedSetting == 'normal':
 camera.capture(jpgFile, quality=settingQuality)
 else:
 orgFrameRate = camera.framerate
 if shutterSpeedSetting == '6 sec':
 camera.framerate = Fraction(1, 6)
 camera.shutter_speed = 6000000
 elif shutterSpeedSetting == '5 sec':
 camera.framerate = Fraction(1, 5)
 camera.shutter_speed = 5000000
 elif shutterSpeedSetting == '4 sec':
 camera.framerate = Fraction(1, 4)
 camera.shutter_speed = 4000000
 elif shutterSpeedSetting == '3 sec':
 camera.framerate = Fraction(1, 3)
 camera.shutter_speed = 3000000
 elif shutterSpeedSetting == '2 sec':
 camera.framerate = Fraction(1, 2)
 camera.shutter_speed = 2000000
 elif shutterSpeedSetting == '1 sec':
 camera.framerate = Fraction(1, 1)
 camera.shutter_speed = 1000000
 elif shutterSpeedSetting == '1/2 sec':
 camera.framerate = Fraction(1, 1)
 camera.shutter_speed = 500000
 elif shutterSpeedSetting == '1/4 sec':
 camera.framerate = Fraction(1, 1)
 camera.shutter_speed = 250000
 #sleep(1)
 camera.capture(jpgFile, quality=settingQuality)
 camera.framerate = orgFrameRate
 camera.shutter_speed = 0
 camera.resolution = (400, 300) #resume preview size
 
 labelCapVal.set(jpgFile)
 elif rqs == RQS_STARTLAPSE:
 rqs=RQS_0
 labelLapseText.set("Timelapse started.")
 btnStartLapse.config(state=tk.DISABLED)
 btnStopLapse.config(state=tk.NORMAL)
 timelapsing = True
 lapseDir = time.strftime("%Y%m%d-%H%M%S")
 os.makedirs(lapseDir)
 
 prefix = lapseDir + "/" + PREFIX_LAPSE
 camera.shutter_speed = camera.exposure_speed
 camera.exposure_mode = 'off'
 g = camera.awb_gains
 camera.awb_mode = 'off'
 camera.awb_gains = g
 
 startTimelapseHandle()
 elif rqs == RQS_STOPLAPSE:
 rqs=RQS_0
 global lapse_rqs
 lapse_rqs = LAPSE_RQS_STOP
 labelLapseText.set("Timelapse stopped.")
 btnStartLapse.config(state=tk.NORMAL)
 btnStopLapse.config(state=tk.DISABLED)
 prefix = PREFIX_IMAGE
 timelapsing = False
 rqsUpdateSetting = True
 elif rqs == RQS_LAPSEEND:
 rqs=RQS_0
 labelLapseText.set("Timelapse ended.")
 btnStartLapse.config(state=tk.NORMAL)
 btnStopLapse.config(state=tk.DISABLED)
 prefix = PREFIX_IMAGE
 timelapsing = False
 rqsUpdateSetting = True
 else:
 stream = io.BytesIO()
 camera.capture(stream, format='jpeg', quality=40)
 stream.seek(0)
 tmpImage = Image.open(stream)
 tmpImg = ImageTk.PhotoImage(tmpImage)
 previewPanel.configure(image = tmpImg)
 #sleep(0.5)
 
 print("Quit") 
 #camera.stop_preview()
def startCamHandler():
 camThread = Thread(target=camHandler)
 camThread.start()
def TimelapseHandle():
 global lapse_rqs
 global rqs
 global prefix
 print("TimelapseHandle started")
 numberOfShot = scaleNumOfShot.get()
 interval = scaleIntervalSec.get()
 
 while True:
 
 if lapse_rqs == LAPSE_RQS_STOP:
 lapse_rqs = LAPSE_RQS_0
 print('LAPSE_RQS_STOP')
 break
 print(numberOfShot)
 rqs = RQS_CAPTURE
 if numberOfShot != 0:
 numberOfShot = numberOfShot-1
 labelLapseText.set(str(numberOfShot))
 if numberOfShot == 0:
 break;
 
 sleep(interval)
 
 rqs = RQS_LAPSEEND
 print("TimelapseHandle ended")
 
def startTimelapseHandle():
 print("TimelapseHandle starting...")
 global lapse_rqs
 lapse_rqs = LAPSE_RQS_0
 timelapseThread = Thread(target=TimelapseHandle)
 timelapseThread.start()
def quit():
 print("quit()")
 global rqs
 global lapse_rqs
 rqs=RQS_QUIT
 lapse_rqs=LAPSE_RQS_STOP
 global tkTop
 tkTop.destroy()
def capture():
 global rqs
 rqs = RQS_CAPTURE
 labelCapVal.set("capturing")
def cbScaleSetting(new_value):
 global rqsUpdateSetting
 rqsUpdateSetting = True
def cbButtons():
 global rqsUpdateSetting
 rqsUpdateSetting = True
 
def lapseScaleSetting(new_value):
 #do nothing
 pass
def cmdStartLapse():
 global rqs
 labelLapseText.set("Timelapse starting...")
 rqs = RQS_STARTLAPSE
def cmdStopLapse():
 global rqs
 labelLapseText.set("Timelapse stopping...")
 rqs = RQS_STOPLAPSE
tkTop = tk.Tk()
tkTop.wm_title("helloraspberrypi.blogspot.com")
tkTop.geometry('1000x650')
myFont = tkFont.Font(size=16)
previewWin = tk.Toplevel(tkTop)
previewWin.title('Preview')
previewWin.geometry('400x300')
previewPanel = tk.Label(previewWin)
previewPanel.pack(side = "bottom", fill = "both", expand = "yes")
#tkButtonQuit = tk.Button(tkTop, text="Quit", command=quit).pack()
tkButtonCapture = tk.Button(
 tkTop, text="Capture", command=capture)
tkButtonCapture.pack()
SCALE_WIDTH = 980;
labelCapVal = tk.StringVar()
tk.Label(tkTop, textvariable=labelCapVal).pack()
notebook = ttk.Notebook(tkTop)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
frame3 = ttk.Frame(notebook)
frame4 = ttk.Frame(notebook)
frame5 = ttk.Frame(notebook)
notebook.add(frame1, text='Setting')
notebook.add(frame2, text='White Balance')
notebook.add(frame3, text='Image Effect')
notebook.add(frame4, text='Control')
notebook.add(frame5, text='Timelapse')
notebook.pack()
# Tab Setting
tk.Label(frame1, text=require('picamera')).pack()
scaleSharpness = tk.Scale(
 frame1,
 from_=-100, to=100,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="sharpness",
 command=cbScaleSetting)
scaleSharpness.set(0)
scaleSharpness.pack(anchor=tk.CENTER)
scaleContrast = tk.Scale(
 frame1,
 from_=-100, to=100,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="contrast",
 command=cbScaleSetting)
scaleContrast.set(0)
scaleContrast.pack(anchor=tk.CENTER)
scaleBrightness = tk.Scale(
 frame1,
 from_=0, to=100,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="brightness",
 command=cbScaleSetting)
scaleBrightness.set(50)
scaleBrightness.pack(anchor=tk.CENTER)
scaleSaturation = tk.Scale(
 frame1,
 from_=-100, to=100,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="saturation",
 command=cbScaleSetting)
scaleSaturation.set(0)
scaleSaturation.pack(anchor=tk.CENTER)
scaleExpCompensation = tk.Scale(
 frame1,
 from_=-25, to=25,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="exposure_compensation",
 command=cbScaleSetting)
scaleExpCompensation.set(0)
scaleExpCompensation.pack(anchor=tk.CENTER)
lfExpMode = ttk.LabelFrame(frame1, text="Exposure Mode")
lfExpMode.pack(fill="x")
varExpMode = tk.StringVar()
varExpMode.set('auto')
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='off',value='off',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='auto',value='auto',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='night',value='night',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='nightpreview',value='nightpreview',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='backlight',value='backlight',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='spotlight',value='spotlight',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='sports',value='sports',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='snow',value='snow',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='beach',value='beach',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='verylong',value='verylong',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='fixedfps',value='fixedfps',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='antishake',value='antishake',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfExpMode, variable=varExpMode,
 text='fireworks',value='fireworks',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfMeterMode = ttk.LabelFrame(frame1, text="Meter Mode")
lfMeterMode.pack(fill="x")
varMeterMode = tk.StringVar()
varMeterMode.set('average')
tk.Radiobutton(lfMeterMode, variable=varMeterMode,
 text='average',value='average',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfMeterMode, variable=varMeterMode,
 text='spot',value='spot',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfMeterMode, variable=varMeterMode,
 text='backlit',value='backlit',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfMeterMode, variable=varMeterMode,
 text='matrix',value='matrix',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
# Tab White Balance
lfAwbMode = ttk.LabelFrame(frame2, text="awb_mode")
lfAwbMode.pack(fill="x")
lfAwbGains = ttk.LabelFrame(frame2, text="awb_gains")
lfAwbGains.pack(fill="x")
labelAwbVar = tk.StringVar()
tk.Label(lfAwbMode, textvariable=labelAwbVar).pack()
#--
AWB_MODES = [
 ("off (set by awb_gains)", "off"),
 ("auto", "auto"),
 ("sunlight", "sunlight"),
 ("cloudy", "cloudy"),
 ("shade", "shade"),
 ("tungsten", "tungsten"),
 ("fluorescent", "fluorescent"),
 ("incandescent", "incandescent"),
 ("flash", "flash"),
 ("horizon", "horizon"),
 ]
varAwbMode = tk.StringVar()
varAwbMode.set("auto")
for text, awbmode in AWB_MODES:
 awbModeBtns = tk.Radiobutton(
 lfAwbMode,
 text=text,
 variable=varAwbMode,
 value=awbmode,
 command=cbButtons)
 awbModeBtns.pack(anchor=tk.W)
#--
scaleGainRed = tk.Scale(
 lfAwbGains,
 from_=0.0, to=8.0,
 resolution=0.1,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="Red",
 command=cbScaleSetting)
scaleGainRed.set(0.0)
scaleGainRed.pack(anchor=tk.CENTER)
scaleGainBlue = tk.Scale(
 lfAwbGains,
 from_=0.0, to=8.0,
 resolution=0.1,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="Blue",
 command=cbScaleSetting)
scaleGainBlue.set(0.0)
scaleGainBlue.pack(anchor=tk.CENTER)
# Tab Image Effect
#For Image effects, ref:
#http://picamera.readthedocs.org/en/latest/api_camera.html?highlight=effect#picamera.camera.PiCamera.image_effect
labelImageEffectVar = tk.StringVar()
tk.Label(frame3, textvariable=labelImageEffectVar).pack()
#-- image_effect
varImageEffect = tk.StringVar()
varImageEffect.set('none')
lfNoParaOpts1 = ttk.Frame(frame3)
lfNoParaOpts1.pack(fill="x")
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='none',value='none',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='negative',value='negative',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='sketch',value='sketch',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='denoise',value='denoise',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='emboss',value='emboss',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='oilpaint',value='oilpaint',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='hatch',value='hatch',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts1, variable=varImageEffect,
 text='gpen',value='gpen',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfNoParaOpts2 = ttk.Frame(frame3)
lfNoParaOpts2.pack(fill="x")
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='pastel',value='pastel',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='saturation',value='saturation',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='washedout',value='washedout',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='cartoon',value='cartoon',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='deinterlace1',value='deinterlace1',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfNoParaOpts2, variable=varImageEffect,
 text='deinterlace2',value='deinterlace2',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfSolarize = ttk.LabelFrame(frame3, text="solarize")
lfSolarize.pack(fill="x")
tk.Radiobutton(lfSolarize, variable=varImageEffect,
 text='solarize',value='solarize',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
cbSolarize_yuv_Var = tk.BooleanVar()
tk.Checkbutton(lfSolarize, text="yuv",
 variable=cbSolarize_yuv_Var, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scSolarize_x0_Var = tk.IntVar()
scSolarize_x0_Var.set(128)
tk.Scale(lfSolarize, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="x0",
 variable=scSolarize_x0_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scSolarize_y0_Var = tk.IntVar()
scSolarize_y0_Var.set(128)
tk.Scale(lfSolarize, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="y0",
 variable=scSolarize_y0_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scSolarize_y1_Var = tk.IntVar()
scSolarize_y1_Var.set(128)
tk.Scale(lfSolarize, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="y1",
 variable=scSolarize_y1_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scSolarize_y2_Var = tk.IntVar()
scSolarize_y2_Var.set(0)
tk.Scale(lfSolarize, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="y2",
 variable=scSolarize_y2_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
lfwatercolor = ttk.LabelFrame(frame3, text="watercolor")
lfwatercolor.pack(fill="x")
tk.Radiobutton(lfwatercolor, variable=varImageEffect,
 text='watercolor',value='watercolor',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
cbWatercolor_uv_Var = tk.BooleanVar()
cbWatercolor_uv_Var.set(False)
tk.Checkbutton(lfwatercolor, text="uv",
 variable=cbWatercolor_uv_Var, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scWatercolor_u_Var = tk.IntVar()
scWatercolor_u_Var.set(0)
tk.Scale(lfwatercolor, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="u",
 variable=scWatercolor_u_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scWatercolor_v_Var = tk.IntVar()
scWatercolor_v_Var.set(0)
tk.Scale(lfwatercolor, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="v",
 variable=scWatercolor_v_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
lffilm = ttk.LabelFrame(frame3, text="film")
lffilm.pack(fill="x")
tk.Radiobutton(lffilm, variable=varImageEffect,
 text='film',value='film',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scFilm_strength_Var = tk.IntVar()
scFilm_strength_Var.set(0)
tk.Scale(lffilm, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="strength",
 variable=scFilm_strength_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scFilm_u_Var = tk.IntVar()
scFilm_u_Var.set(0)
tk.Scale(lffilm, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="u",
 variable=scFilm_u_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scFilm_v_Var = tk.IntVar()
scFilm_v_Var.set(0)
tk.Scale(lffilm, from_=0, to=255,
 orient=tk.HORIZONTAL, length=200, label="v",
 variable=scFilm_v_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
lfblur = ttk.LabelFrame(frame3, text="blur")
lfblur.pack(fill="x")
tk.Radiobutton(lfblur, variable=varImageEffect,
 text='blur',value='blur',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scBlur_size_Var = tk.IntVar()
scBlur_size_Var.set(1)
tk.Scale(lfblur, from_=1, to=2,
 orient=tk.HORIZONTAL, length=100, label="size",
 variable=scBlur_size_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
lfcolorswap = ttk.LabelFrame(frame3, text="colorswap")
lfcolorswap.pack(fill="x")
tk.Radiobutton(lfcolorswap, variable=varImageEffect,
 text='colorswap',value='colorswap',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
cbColorswap_dir_Var = tk.BooleanVar()
cbColorswap_dir_Var.set(False)
tk.Checkbutton(lfcolorswap, text="dir - 0:RGB to BGR/1:RGB to BRG",
 variable=cbColorswap_dir_Var, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfposterise = ttk.LabelFrame(frame3, text="posterise")
lfposterise.pack(fill="x")
tk.Radiobutton(lfposterise, variable=varImageEffect,
 text='posterise',value='posterise',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scPosterise_steps_Var = tk.IntVar()
scPosterise_steps_Var.set(4)
tk.Scale(lfposterise, from_=2, to=32,
 orient=tk.HORIZONTAL, length=200, label="steps",
 variable=scPosterise_steps_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
lfcolorpoint = ttk.LabelFrame(frame3, text="colorpoint")
lfcolorpoint.pack(fill="x")
tk.Radiobutton(lfcolorpoint, variable=varImageEffect,
 text='colorpoint',value='colorpoint',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
quadrantVar = tk.IntVar()
quadrantVar.set(0)
tk.Radiobutton(lfcolorpoint, text="green",
 variable=quadrantVar, value=0, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfcolorpoint, text="red/yellow",
 variable=quadrantVar, value=1, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfcolorpoint, text="blue",
 variable=quadrantVar, value=2, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfcolorpoint, text="purple",
 variable=quadrantVar, value=3, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfcolorbalance = ttk.LabelFrame(frame3, text="colorbalance: I can't see the effect!")
lfcolorbalance.pack(fill="x")
tk.Radiobutton(lfcolorbalance, variable=varImageEffect,
 text='colorbalance',value='colorbalance',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_lens_Var = tk.DoubleVar()
scColorbalance_lens_Var.set(0)
tk.Scale(lfcolorbalance, from_=0, to=256,
 orient=tk.HORIZONTAL, length=140, label="lens",
 variable=scColorbalance_lens_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_r_Var = tk.DoubleVar()
scColorbalance_r_Var.set(1)
tk.Scale(lfcolorbalance, from_=0, to=256,
 orient=tk.HORIZONTAL, length=140, label="r",
 variable=scColorbalance_r_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_g_Var = tk.DoubleVar()
scColorbalance_g_Var.set(1)
tk.Scale(lfcolorbalance, from_=0, to=256,
 orient=tk.HORIZONTAL, length=140, label="g",
 variable=scColorbalance_g_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_b_Var = tk.DoubleVar()
scColorbalance_b_Var.set(1)
tk.Scale(lfcolorbalance, from_=0, to=256,
 orient=tk.HORIZONTAL, length=140, label="b",
 variable=scColorbalance_b_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_u_Var = tk.IntVar()
scColorbalance_u_Var.set(0)
tk.Scale(lfcolorbalance, from_=0, to=255,
 orient=tk.HORIZONTAL, length=140, label="u",
 variable=scColorbalance_u_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
scColorbalance_v_Var = tk.IntVar()
scColorbalance_v_Var.set(0)
tk.Scale(lfcolorbalance, from_=0, to=255,
 orient=tk.HORIZONTAL, length=140, label="v",
 variable=scColorbalance_v_Var, command=cbScaleSetting).pack(anchor=tk.W, side=tk.LEFT)
# Tab Control
lfISO = ttk.LabelFrame(frame4, text="ISO")
lfISO.pack(fill="x")
varIso = tk.IntVar()
tk.Radiobutton(lfISO, variable=varIso,
 text='auto',value='0',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='100',value='100',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='200',value='200',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='320',value='320',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='400',value='400',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='500',value='500',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='640',value='640',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfISO, variable=varIso,
 text='800',value='800',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfDRC = ttk.LabelFrame(frame4, text="Dynamic Range Compression")
lfDRC.pack(fill="x")
varDrc = tk.StringVar()
varDrc.set('off')
tk.Radiobutton(lfDRC, variable=varDrc,
 text='off',value='off',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfDRC, variable=varDrc,
 text='low',value='low',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfDRC, variable=varDrc,
 text='medium',value='medium',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfDRC, variable=varDrc,
 text='high',value='high',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfRotation = ttk.LabelFrame(frame4, text="Rotation")
lfRotation.pack(fill="x")
varRotation = tk.IntVar()
varRotation.set(270)
tk.Radiobutton(lfRotation, variable=varRotation,
 text='0',value='0',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfRotation, variable=varRotation,
 text='90',value='90',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfRotation, variable=varRotation,
 text='180',value='180',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfRotation, variable=varRotation,
 text='270',value='270',command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
lfFlip = ttk.LabelFrame(frame4, text="Flip")
lfFlip.pack(fill="x")
varHFlip = tk.BooleanVar()
varHFlip.set(False)
tk.Checkbutton(lfFlip, text="hflip",
 variable=varHFlip, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
varVFlip = tk.BooleanVar()
varVFlip.set(False)
tk.Checkbutton(lfFlip, text="vflip",
 variable=varVFlip, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
# Resolution
lfResolution = ttk.LabelFrame(frame4, text="Resolution")
lfResolution.pack(fill="x")
varResolution = tk.StringVar()
varResolution.set('1280x720')
tk.Radiobutton(lfResolution, variable=varResolution,
 text='640x480',value='640x480').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='800x400',value='800x600').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='1280x720',value='1280x720').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='1296x730',value='1296x730').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='1296x972',value='1296x972').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='1600x1200',value='1600x1200').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='1920x1080',value='1920x1080').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(lfResolution, variable=varResolution,
 text='2592x1944',value='2592x1944').pack(anchor=tk.W, side=tk.LEFT)
# Quality
lfQuality = ttk.LabelFrame(frame4, text="Quality")
lfQuality.pack(fill="x")
varQuality = tk.IntVar()
varQuality.set(85)
tk.Scale(lfQuality, from_=10, to=100,
 orient=tk.HORIZONTAL, length=600, label="%",
 variable=varQuality).pack(anchor=tk.W, side=tk.LEFT)
lfDenoise = ttk.LabelFrame(frame4, text="image_denoise")
lfDenoise.pack(fill="x")
varDenoise = tk.BooleanVar()
varDenoise.set(True)
tk.Checkbutton(lfDenoise, text="image_denoise",
 variable=varDenoise, command=cbButtons).pack(anchor=tk.W, side=tk.LEFT)
# Shutter Speed
lfShuuterSpeed = ttk.LabelFrame(frame4, text="Slow Shutter (caution: NOT work as expected)")
lfShuuterSpeed.pack(fill="x")
frameShuuterSpeed1 = tk.Frame(lfShuuterSpeed)
frameShuuterSpeed1.pack(fill="x")
frameShuuterSpeed2 = tk.Frame(lfShuuterSpeed)
frameShuuterSpeed2.pack(fill="x")
varShutterSpeed = tk.StringVar()
varShutterSpeed.set('normal')
tk.Radiobutton(frameShuuterSpeed1, variable=varShutterSpeed,
 text='normal',value='normal').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='1/4 sec',value='1/4 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='1/2 sec',value='1/2 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='1 sec',value='1 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='2 sec',value='2 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='3 sec',value='3 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='4 sec',value='4 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='5 sec',value='5 sec').pack(anchor=tk.W, side=tk.LEFT)
tk.Radiobutton(frameShuuterSpeed2, variable=varShutterSpeed,
 text='6 sec',value='6 sec').pack(anchor=tk.W, side=tk.LEFT)
#---------------------------------------
#TimeLapse
lfTimelapse = ttk.LabelFrame(frame5, text="Timelapse")
lfTimelapse.pack(fill="x")
btnStartLapse = tk.Button(
 lfTimelapse, text="Start TimeLapse", state=tk.NORMAL,
 font=myFont, command=cmdStartLapse)
btnStartLapse.pack(anchor=tk.W, side=tk.LEFT)
btnStopLapse = tk.Button(
 lfTimelapse, text="Stop TimeLapse", state=tk.DISABLED,
 font=myFont, command=cmdStopLapse)
btnStopLapse.pack(anchor=tk.W, side=tk.LEFT)
labelLapseText = tk.StringVar()
tk.Label(lfTimelapse, textvariable=labelLapseText).pack(anchor=tk.W, side=tk.LEFT)
lfInterval = ttk.LabelFrame(frame5, text="interval")
lfInterval.pack(fill="x")
scaleIntervalSec = tk.Scale(
 lfInterval,
 from_=5, to=60,
 resolution=5,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="second",
 font=myFont,
 command=lapseScaleSetting)
scaleIntervalSec.set(5)
scaleIntervalSec.pack(anchor=tk.CENTER)
lfNumOfShot = ttk.LabelFrame(frame5, text="Number of shot")
lfNumOfShot.pack(fill="x")
scaleNumOfShot= tk.Scale(
 lfNumOfShot,
 from_=0, to=300,
 resolution=1,
 length=SCALE_WIDTH,
 orient=tk.HORIZONTAL,
 label="# (0 = continue until 'Stop Timelapse' button pressed)",
 font=myFont,
 command=lapseScaleSetting)
scaleNumOfShot.set(0)
scaleNumOfShot.pack(anchor=tk.CENTER)
labelLockedSetting = tk.StringVar()
tk.Label(frame5, textvariable=labelLockedSetting).pack()
#=======================================
print("start")
startCamHandler()
tk.mainloop()

Once photos taking stopped, switch to the new directory under pyLapse. All the photos named with timestamp.


Samples:
- Raspberry Pi Camera Module Timelapse video
- Assembling of 2WD Smart Robot Car
- Thunder (timelapse) captured by Raspberry Pi NoIR Camera Module
- Raspberry Pi NoIR Camera V2 Timelapse
- RPi Camera Module NoIR V2 Timelapse - 2016年05月08日



Subscribe to: Comments (Atom)

AltStyle によって変換されたページ (->オリジナル) /